diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 deleted file mode 100644 index b49d77ba44b24fe6d69f6bbe75139b3b5dc23075..0000000000000000000000000000000000000000 --- a/venv/bin/Activate.ps1 +++ /dev/null @@ -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" diff --git a/venv/bin/activate b/venv/bin/activate deleted file mode 100644 index d13b1f826e23682d09611c6f1c0f0eeacc07a355..0000000000000000000000000000000000000000 --- a/venv/bin/activate +++ /dev/null @@ -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=/mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/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 diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh deleted file mode 100644 index a40bc4e6268736027cb616a34bb071ad7a669233..0000000000000000000000000000000000000000 --- a/venv/bin/activate.csh +++ /dev/null @@ -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 . -# Ported to Python 3.3 venv by Andrew Svetlov - -alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/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 diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish deleted file mode 100644 index 62e6c0fd4db5f02557a89ccec87495d0e109e616..0000000000000000000000000000000000000000 --- a/venv/bin/activate.fish +++ /dev/null @@ -1,69 +0,0 @@ -# This file must be used with "source /bin/activate.fish" *from fish* -# (https://fishshell.com/); you cannot run it directly. - -function deactivate -d "Exit virtual environment and return to normal shell environment" - # reset old environment variables - if test -n "$_OLD_VIRTUAL_PATH" - set -gx PATH $_OLD_VIRTUAL_PATH - set -e _OLD_VIRTUAL_PATH - end - if test -n "$_OLD_VIRTUAL_PYTHONHOME" - set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME - set -e _OLD_VIRTUAL_PYTHONHOME - end - - if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - 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 /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/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 diff --git a/venv/bin/hf b/venv/bin/hf deleted file mode 100644 index cbc9c8420d55f2ce3cd43a7197507a2ee9181507..0000000000000000000000000000000000000000 --- a/venv/bin/hf +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from huggingface_hub.cli.hf import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/httpx b/venv/bin/httpx deleted file mode 100644 index 860a0e06d70db8d6a7f7b9b29d8fef859f3a511b..0000000000000000000000000000000000000000 --- a/venv/bin/httpx +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- 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()) diff --git a/venv/bin/markdown-it b/venv/bin/markdown-it deleted file mode 100644 index 595562b406624ac9422921d9b64e197cf8af79ea..0000000000000000000000000000000000000000 --- a/venv/bin/markdown-it +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from markdown_it.cli.parse import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip b/venv/bin/pip deleted file mode 100644 index e9e71b56767b71744f7140c6c145953e958d3fb8..0000000000000000000000000000000000000000 --- a/venv/bin/pip +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 deleted file mode 100644 index e9e71b56767b71744f7140c6c145953e958d3fb8..0000000000000000000000000000000000000000 --- a/venv/bin/pip3 +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip3.10 b/venv/bin/pip3.10 deleted file mode 100644 index e9e71b56767b71744f7140c6c145953e958d3fb8..0000000000000000000000000000000000000000 --- a/venv/bin/pip3.10 +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pygmentize b/venv/bin/pygmentize deleted file mode 100644 index fa7a0cc86286593d0a3a0992c2d8972f30b30389..0000000000000000000000000000000000000000 --- a/venv/bin/pygmentize +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from pygments.cmdline import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python deleted file mode 100644 index 84d6fe34b073ce9c78a61afab00b8a56ab8f9200..0000000000000000000000000000000000000000 --- a/venv/bin/python +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f54854453331ddc3cb58abb15d4d24cd4964d9474fc31c3932348351b991b398 -size 5937672 diff --git a/venv/bin/python3 b/venv/bin/python3 deleted file mode 100644 index 84d6fe34b073ce9c78a61afab00b8a56ab8f9200..0000000000000000000000000000000000000000 --- a/venv/bin/python3 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f54854453331ddc3cb58abb15d4d24cd4964d9474fc31c3932348351b991b398 -size 5937672 diff --git a/venv/bin/python3.10 b/venv/bin/python3.10 deleted file mode 100644 index 84d6fe34b073ce9c78a61afab00b8a56ab8f9200..0000000000000000000000000000000000000000 --- a/venv/bin/python3.10 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f54854453331ddc3cb58abb15d4d24cd4964d9474fc31c3932348351b991b398 -size 5937672 diff --git a/venv/bin/tiny-agents b/venv/bin/tiny-agents deleted file mode 100644 index 26ca01aff8959de3ff5ce7ba27f26d86078a6cd0..0000000000000000000000000000000000000000 --- a/venv/bin/tiny-agents +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from huggingface_hub.inference._mcp.cli import app -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(app()) diff --git a/venv/bin/tqdm b/venv/bin/tqdm deleted file mode 100644 index 892c53fc3babe9aaa73915d2ea3e846af6d3b389..0000000000000000000000000000000000000000 --- a/venv/bin/tqdm +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- 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()) diff --git a/venv/bin/typer b/venv/bin/typer deleted file mode 100644 index 6b2fd3cf89dbf3e8cc229ed7313aeb7e8c54ff37..0000000000000000000000000000000000000000 --- a/venv/bin/typer +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -'''exec' /mnt/llm-data/users/xieshuai/codes/hf_model/omni/deepseek_40b/20260211-dpo-0210-0208-v2-dpoaddid-965-mtp-qiangzhifeisikao/fp8_model/venv/bin/python3 "$0" "$@" -' ''' -# -*- coding: utf-8 -*- -import re -import sys -from typer.cli import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/lib/python3.10/site-packages/__pycache__/typing_extensions.cpython-310.pyc b/venv/lib/python3.10/site-packages/__pycache__/typing_extensions.cpython-310.pyc deleted file mode 100644 index 34d102061deb5be6563b1653a4d110b00eb87191..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/__pycache__/typing_extensions.cpython-310.pyc +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:996f8c7f9bce309b7dddbfca49de5e2405f1927645499a2fe3207ed41a341208 -size 115714 diff --git a/venv/lib/python3.10/site-packages/_distutils_hack/__init__.py b/venv/lib/python3.10/site-packages/_distutils_hack/__init__.py deleted file mode 100644 index f707416286b22ddbdcf84f60b6ad38ded604bdfc..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/_distutils_hack/__init__.py +++ /dev/null @@ -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 diff --git a/venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 03069921dd2cd1192ad36d093617806d4da201d0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc b/venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc deleted file mode 100644 index fb88e12cd0bf4d4441ee3c99536775bceb1179c0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/_distutils_hack/override.py b/venv/lib/python3.10/site-packages/_distutils_hack/override.py deleted file mode 100644 index 2cc433a4a55e3b41fa31089918fb62096092f89f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/_distutils_hack/override.py +++ /dev/null @@ -1 +0,0 @@ -__import__('_distutils_hack').do_override() diff --git a/venv/lib/python3.10/site-packages/_yaml/__init__.py b/venv/lib/python3.10/site-packages/_yaml/__init__.py deleted file mode 100644 index 7baa8c4b68127d5cdf0be9a799429e61347c2694..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/_yaml/__init__.py +++ /dev/null @@ -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__ = '' diff --git a/venv/lib/python3.10/site-packages/_yaml/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/_yaml/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index da2030f2afebbfd4cc426b9f33beeb3a7e3b4280..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/_yaml/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/METADATA b/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/METADATA deleted file mode 100644 index 9bf7a9e800778c5a8c3f1357450ab0849d13d953..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/METADATA +++ /dev/null @@ -1,145 +0,0 @@ -Metadata-Version: 2.4 -Name: annotated-doc -Version: 0.0.4 -Summary: Document parameters, class attributes, return types, and variables inline, with Annotated. -Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= -License-Expression: MIT -License-File: LICENSE -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Application Frameworks -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development -Classifier: Typing :: Typed -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Project-URL: Homepage, https://github.com/fastapi/annotated-doc -Project-URL: Documentation, https://github.com/fastapi/annotated-doc -Project-URL: Repository, https://github.com/fastapi/annotated-doc -Project-URL: Issues, https://github.com/fastapi/annotated-doc/issues -Project-URL: Changelog, https://github.com/fastapi/annotated-doc/release-notes.md -Requires-Python: >=3.8 -Description-Content-Type: text/markdown - -# Annotated Doc - -Document parameters, class attributes, return types, and variables inline, with `Annotated`. - - - Test - - - Coverage - - - Package version - - - Supported Python versions - - -## Installation - -```bash -pip install annotated-doc -``` - -Or with `uv`: - -```Python -uv add annotated-doc -``` - -## Usage - -Import `Doc` and pass a single literal string with the documentation for the specific parameter, class attribute, return type, or variable. - -For example, to document a parameter `name` in a function `hi` you could do: - -```Python -from typing import Annotated - -from annotated_doc import Doc - -def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None: - print(f"Hi, {name}!") -``` - -You can also use it to document class attributes: - -```Python -from typing import Annotated - -from annotated_doc import Doc - -class User: - name: Annotated[str, Doc("The user's name")] - age: Annotated[int, Doc("The user's age")] -``` - -The same way, you could document return types and variables, or anything that could have a type annotation with `Annotated`. - -## Who Uses This - -`annotated-doc` was made for: - -* [FastAPI](https://fastapi.tiangolo.com/) -* [Typer](https://typer.tiangolo.com/) -* [SQLModel](https://sqlmodel.tiangolo.com/) -* [Asyncer](https://asyncer.tiangolo.com/) - -`annotated-doc` is supported by [griffe-typingdoc](https://github.com/mkdocstrings/griffe-typingdoc), which powers reference documentation like the one in the [FastAPI Reference](https://fastapi.tiangolo.com/reference/). - -## Reasons not to use `annotated-doc` - -You are already comfortable with one of the existing docstring formats, like: - -* Sphinx -* numpydoc -* Google -* Keras - -Your team is already comfortable using them. - -You prefer having the documentation about parameters all together in a docstring, separated from the code defining them. - -You care about a specific set of users, using one specific editor, and that editor already has support for the specific docstring format you use. - -## Reasons to use `annotated-doc` - -* No micro-syntax to learn for newcomers, it’s **just Python** syntax. -* **Editing** would be already fully supported by default by any editor (current or future) supporting Python syntax, including syntax errors, syntax highlighting, etc. -* **Rendering** would be relatively straightforward to implement by static tools (tools that don't need runtime execution), as the information can be extracted from the AST they normally already create. -* **Deduplication of information**: the name of a parameter would be defined in a single place, not duplicated inside of a docstring. -* **Elimination** of the possibility of having **inconsistencies** when removing a parameter or class variable and **forgetting to remove** its documentation. -* **Minimization** of the probability of adding a new parameter or class variable and **forgetting to add its documentation**. -* **Elimination** of the possibility of having **inconsistencies** between the **name** of a parameter in the **signature** and the name in the docstring when it is renamed. -* **Access** to the documentation string for each symbol at **runtime**, including existing (older) Python versions. -* A more formalized way to document other symbols, like type aliases, that could use Annotated. -* **Support** for apps using FastAPI, Typer and others. -* **AI Accessibility**: AI tools will have an easier way understanding each parameter as the distance from documentation to parameter is much closer. - -## History - -I ([@tiangolo](https://github.com/tiangolo)) originally wanted for this to be part of the Python standard library (in [PEP 727](https://peps.python.org/pep-0727/)), but the proposal was withdrawn as there was a fair amount of negative feedback and opposition. - -The conclusion was that this was better done as an external effort, in a third-party library. - -So, here it is, with a simpler approach, as a third-party library, in a way that can be used by others, starting with FastAPI and friends. - -## License - -This project is licensed under the terms of the MIT license. diff --git a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/RECORD b/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/RECORD deleted file mode 100644 index 314d720903083f3d2a3098797ced384c432d8512..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/RECORD +++ /dev/null @@ -1,11 +0,0 @@ -annotated_doc-0.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -annotated_doc-0.0.4.dist-info/METADATA,sha256=Irm5KJua33dY2qKKAjJ-OhKaVBVIfwFGej_dSe3Z1TU,6566 -annotated_doc-0.0.4.dist-info/RECORD,, -annotated_doc-0.0.4.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90 -annotated_doc-0.0.4.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34 -annotated_doc-0.0.4.dist-info/licenses/LICENSE,sha256=__Fwd5pqy_ZavbQFwIfxzuF4ZpHkqWpANFF-SlBKDN8,1086 -annotated_doc/__init__.py,sha256=VuyxxUe80kfEyWnOrCx_Bk8hybo3aKo6RYBlkBBYW8k,52 -annotated_doc/__pycache__/__init__.cpython-310.pyc,, -annotated_doc/__pycache__/main.cpython-310.pyc,, -annotated_doc/main.py,sha256=5Zfvxv80SwwLqpRW73AZyZyiM4bWma9QWRbp_cgD20s,1075 -annotated_doc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/WHEEL b/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/WHEEL deleted file mode 100644 index 045c8acdea31cbca5be986e915f784c1aafc720f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: pdm-backend (2.4.5) -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt b/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt deleted file mode 100644 index c3ad4726d437022e5c606a4206ffb6007347a008..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt +++ /dev/null @@ -1,4 +0,0 @@ -[console_scripts] - -[gui_scripts] - diff --git a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE deleted file mode 100644 index 7a254464cc78ccea32b3ded00513c44c4e4da412..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2025 Sebastián Ramírez - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/venv/lib/python3.10/site-packages/annotated_doc/__init__.py b/venv/lib/python3.10/site-packages/annotated_doc/__init__.py deleted file mode 100644 index a0152a7d12abc2db37fb26e764a61e0c894a43f3..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .main import Doc as Doc - -__version__ = "0.0.4" diff --git a/venv/lib/python3.10/site-packages/annotated_doc/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/annotated_doc/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 7295609aac81d084cdf1a16f20072b9b365e35a4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/annotated_doc/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/annotated_doc/__pycache__/main.cpython-310.pyc b/venv/lib/python3.10/site-packages/annotated_doc/__pycache__/main.cpython-310.pyc deleted file mode 100644 index 2f6f79da91cd15445d55345492a352c605702215..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/annotated_doc/__pycache__/main.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/annotated_doc/main.py b/venv/lib/python3.10/site-packages/annotated_doc/main.py deleted file mode 100644 index 7063c59e4500a1d02bfc9b41887f9e95f8163507..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/annotated_doc/main.py +++ /dev/null @@ -1,36 +0,0 @@ -class Doc: - """Define the documentation of a type annotation using `Annotated`, to be - used in class attributes, function and method parameters, return values, - and variables. - - The value should be a positional-only string literal to allow static tools - like editors and documentation generators to use it. - - This complements docstrings. - - The string value passed is available in the attribute `documentation`. - - Example: - - ```Python - from typing import Annotated - from annotated_doc import Doc - - def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None: - print(f"Hi, {name}!") - ``` - """ - - def __init__(self, documentation: str, /) -> None: - self.documentation = documentation - - def __repr__(self) -> str: - return f"Doc({self.documentation!r})" - - def __hash__(self) -> int: - return hash(self.documentation) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Doc): - return NotImplemented - return self.documentation == other.documentation diff --git a/venv/lib/python3.10/site-packages/annotated_doc/py.typed b/venv/lib/python3.10/site-packages/annotated_doc/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/METADATA b/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/METADATA deleted file mode 100644 index dbeb1989ba35da34a15e015e0225304dcd140331..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/METADATA +++ /dev/null @@ -1,96 +0,0 @@ -Metadata-Version: 2.4 -Name: anyio -Version: 4.12.1 -Summary: High-level concurrency and networking framework on top of asyncio or Trio -Author-email: Alex Grönholm -License-Expression: MIT -Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/ -Project-URL: Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html -Project-URL: Source code, https://github.com/agronholm/anyio -Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Framework :: AnyIO -Classifier: Typing :: Typed -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: exceptiongroup>=1.0.2; python_version < "3.11" -Requires-Dist: idna>=2.8 -Requires-Dist: typing_extensions>=4.5; python_version < "3.13" -Provides-Extra: trio -Requires-Dist: trio>=0.32.0; python_version >= "3.10" and extra == "trio" -Requires-Dist: trio>=0.31.0; python_version < "3.10" and extra == "trio" -Dynamic: license-file - -.. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg - :target: https://github.com/agronholm/anyio/actions/workflows/test.yml - :alt: Build Status -.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master - :target: https://coveralls.io/github/agronholm/anyio?branch=master - :alt: Code Coverage -.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest - :target: https://anyio.readthedocs.io/en/latest/?badge=latest - :alt: Documentation -.. image:: https://badges.gitter.im/gitterHQ/gitter.svg - :target: https://gitter.im/python-trio/AnyIO - :alt: Gitter chat - -AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or -Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony -with the native SC of Trio itself. - -Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or -Trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full -refactoring necessary. It will blend in with the native libraries of your chosen backend. - -To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it -`here `_. - -Documentation -------------- - -View full documentation at: https://anyio.readthedocs.io/ - -Features --------- - -AnyIO offers the following functionality: - -* Task groups (nurseries_ in trio terminology) -* High-level networking (TCP, UDP and UNIX sockets) - - * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python - 3.8) - * async/await style UDP sockets (unlike asyncio where you still have to use Transports and - Protocols) - -* A versatile API for byte streams and object streams -* Inter-task synchronization and communication (locks, conditions, events, semaphores, object - streams) -* Worker threads -* Subprocesses -* Subinterpreter support for code parallelization (on Python 3.13 and later) -* Asynchronous file I/O (using worker threads) -* Signal handling -* Asynchronous version of the functools_ module - -AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures. -It even works with the popular Hypothesis_ library. - -.. _asyncio: https://docs.python.org/3/library/asyncio.html -.. _Trio: https://github.com/python-trio/trio -.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency -.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning -.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs -.. _pytest: https://docs.pytest.org/en/latest/ -.. _functools: https://docs.python.org/3/library/functools.html -.. _Hypothesis: https://hypothesis.works/ diff --git a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/RECORD b/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/RECORD deleted file mode 100644 index 310e0e13c166a4088e978cf11228126aa021befc..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/RECORD +++ /dev/null @@ -1,92 +0,0 @@ -anyio-4.12.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -anyio-4.12.1.dist-info/METADATA,sha256=DfiDab9Tmmcfy802lOLTMEHJQShkOSbopCwqCYbLuJk,4277 -anyio-4.12.1.dist-info/RECORD,, -anyio-4.12.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 -anyio-4.12.1.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39 -anyio-4.12.1.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081 -anyio-4.12.1.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6 -anyio/__init__.py,sha256=7iDVqMUprUuKNY91FuoKqayAhR-OY136YDPI6P78HHk,6170 -anyio/__pycache__/__init__.cpython-310.pyc,, -anyio/__pycache__/from_thread.cpython-310.pyc,, -anyio/__pycache__/functools.cpython-310.pyc,, -anyio/__pycache__/lowlevel.cpython-310.pyc,, -anyio/__pycache__/pytest_plugin.cpython-310.pyc,, -anyio/__pycache__/to_interpreter.cpython-310.pyc,, -anyio/__pycache__/to_process.cpython-310.pyc,, -anyio/__pycache__/to_thread.cpython-310.pyc,, -anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/_backends/__pycache__/__init__.cpython-310.pyc,, -anyio/_backends/__pycache__/_asyncio.cpython-310.pyc,, -anyio/_backends/__pycache__/_trio.cpython-310.pyc,, -anyio/_backends/_asyncio.py,sha256=xG6qv60mgGnL0mK82dxjH2b8hlkMlJ-x2BqIq3qv70Y,98863 -anyio/_backends/_trio.py,sha256=30Rctb7lm8g63ZHljVPVnj5aH-uK6oQvphjwUBoAzuI,41456 -anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/_core/__pycache__/__init__.cpython-310.pyc,, -anyio/_core/__pycache__/_asyncio_selector_thread.cpython-310.pyc,, -anyio/_core/__pycache__/_contextmanagers.cpython-310.pyc,, -anyio/_core/__pycache__/_eventloop.cpython-310.pyc,, -anyio/_core/__pycache__/_exceptions.cpython-310.pyc,, -anyio/_core/__pycache__/_fileio.cpython-310.pyc,, -anyio/_core/__pycache__/_resources.cpython-310.pyc,, -anyio/_core/__pycache__/_signals.cpython-310.pyc,, -anyio/_core/__pycache__/_sockets.cpython-310.pyc,, -anyio/_core/__pycache__/_streams.cpython-310.pyc,, -anyio/_core/__pycache__/_subprocesses.cpython-310.pyc,, -anyio/_core/__pycache__/_synchronization.cpython-310.pyc,, -anyio/_core/__pycache__/_tasks.cpython-310.pyc,, -anyio/_core/__pycache__/_tempfile.cpython-310.pyc,, -anyio/_core/__pycache__/_testing.cpython-310.pyc,, -anyio/_core/__pycache__/_typedattr.cpython-310.pyc,, -anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626 -anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215 -anyio/_core/_eventloop.py,sha256=c2EdcBX-xnKwxPcC4Pjn3_qG9I-x4IWFO2R9RqCGjM4,6448 -anyio/_core/_exceptions.py,sha256=Y3aq-Wxd7Q2HqwSg7nZPvRsHEuGazv_qeet6gqEBdPk,4407 -anyio/_core/_fileio.py,sha256=uc7t10Vb-If7GbdWM_zFf-ajUe6uek63fSt7IBLlZW0,25731 -anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435 -anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016 -anyio/_core/_sockets.py,sha256=RBXHcUqZt5gg_-OOfgHVv8uq2FSKk1uVUzTdpjBoI1o,34977 -anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806 -anyio/_core/_subprocesses.py,sha256=EXm5igL7dj55iYkPlbYVAqtbqxJxjU-6OndSTIx9SRg,8047 -anyio/_core/_synchronization.py,sha256=MgVVqFzvt580tHC31LiOcq1G6aryut--xRG4Ff8KwxQ,20869 -anyio/_core/_tasks.py,sha256=pVB7K6AAulzUM8YgXAeqNZG44nSyZ1bYJjH8GznC00I,5435 -anyio/_core/_tempfile.py,sha256=lHb7CW4FyIlpkf5ADAf4VmLHCKwEHF9nxqNyBCFFUiA,19697 -anyio/_core/_testing.py,sha256=u7MPqGXwpTxqI7hclSdNA30z2GH1Nw258uwKvy_RfBg,2340 -anyio/_core/_typedattr.py,sha256=P4ozZikn3-DbpoYcvyghS_FOYAgbmUxeoU8-L_07pZM,2508 -anyio/abc/__init__.py,sha256=6mWhcl_pGXhrgZVHP_TCfMvIXIOp9mroEFM90fYCU_U,2869 -anyio/abc/__pycache__/__init__.cpython-310.pyc,, -anyio/abc/__pycache__/_eventloop.cpython-310.pyc,, -anyio/abc/__pycache__/_resources.cpython-310.pyc,, -anyio/abc/__pycache__/_sockets.cpython-310.pyc,, -anyio/abc/__pycache__/_streams.cpython-310.pyc,, -anyio/abc/__pycache__/_subprocesses.cpython-310.pyc,, -anyio/abc/__pycache__/_tasks.cpython-310.pyc,, -anyio/abc/__pycache__/_testing.cpython-310.pyc,, -anyio/abc/_eventloop.py,sha256=GlzgB3UJGgG6Kr7olpjOZ-o00PghecXuofVDQ_5611Q,10749 -anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783 -anyio/abc/_sockets.py,sha256=ECTY0jLEF18gryANHR3vFzXzGdZ-xPwELq1QdgOb0Jo,13258 -anyio/abc/_streams.py,sha256=005GKSCXGprxnhucILboSqc2JFovECZk9m3p-qqxXVc,7640 -anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067 -anyio/abc/_tasks.py,sha256=KC7wrciE48AINOI-AhPutnFhe1ewfP7QnamFlDzqesQ,3721 -anyio/abc/_testing.py,sha256=tBJUzkSfOXJw23fe8qSJ03kJlShOYjjaEyFB6k6MYT8,1821 -anyio/from_thread.py,sha256=L-0w1HxJ6BSb-KuVi57k5Tkc3yzQrx3QK5tAxMPcY-0,19141 -anyio/functools.py,sha256=HWj7GBEmc0Z-mZg3uok7Z7ZJn0rEC_0Pzbt0nYUDaTQ,10973 -anyio/lowlevel.py,sha256=AyKLVK3LaWSoK39LkCKxE4_GDMLKZBNqTrLUgk63y80,5158 -anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/pytest_plugin.py,sha256=3jAFQn0jv_pyoWE2GBBlHaj9sqXj4e8vob0_hgrsXE8,10244 -anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/streams/__pycache__/__init__.cpython-310.pyc,, -anyio/streams/__pycache__/buffered.cpython-310.pyc,, -anyio/streams/__pycache__/file.cpython-310.pyc,, -anyio/streams/__pycache__/memory.cpython-310.pyc,, -anyio/streams/__pycache__/stapled.cpython-310.pyc,, -anyio/streams/__pycache__/text.cpython-310.pyc,, -anyio/streams/__pycache__/tls.cpython-310.pyc,, -anyio/streams/buffered.py,sha256=2R3PeJhe4EXrdYqz44Y6-Eg9R6DrmlsYrP36Ir43-po,6263 -anyio/streams/file.py,sha256=4WZ7XGz5WNu39FQHvqbe__TQ0HDP9OOhgO1mk9iVpVU,4470 -anyio/streams/memory.py,sha256=F0zwzvFJKAhX_LRZGoKzzqDC2oMM-f-yyTBrEYEGOaU,10740 -anyio/streams/stapled.py,sha256=T8Xqwf8K6EgURPxbt1N4i7A8BAk-gScv-GRhjLXIf_o,4390 -anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765 -anyio/streams/tls.py,sha256=Jpxy0Mfbcp1BxHCwE-YjSSFaLnIBbnnwur-excYThs4,15368 -anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100 -anyio/to_process.py,sha256=J7gAA_YOuoHqnpDAf5fm1Qu6kOmTzdFbiDNvnV755vk,9798 -anyio/to_thread.py,sha256=menEgXYmUV7Fjg_9WqCV95P9MAtQS8BzPGGcWB_QnfQ,2687 diff --git a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/WHEEL b/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/WHEEL deleted file mode 100644 index e7fa31b6f3f78deb1022c1f7927f07d4d16da822..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/entry_points.txt b/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/entry_points.txt deleted file mode 100644 index 44dd9bdc3039122cc98014c1439ca254313fd014..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[pytest11] -anyio = anyio.pytest_plugin diff --git a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE deleted file mode 100644 index 104eebf5a3002fccdaceef3a4cb936173c1c2035..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Alex Grönholm - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/top_level.txt b/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/top_level.txt deleted file mode 100644 index c77c069ecc9b7f8b1f97dbcfec905725db0253a8..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio-4.12.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -anyio diff --git a/venv/lib/python3.10/site-packages/anyio/__init__.py b/venv/lib/python3.10/site-packages/anyio/__init__.py deleted file mode 100644 index d23c5a5a27878561b79551da9513cf600dce5005..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/__init__.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import annotations - -from ._core._contextmanagers import AsyncContextManagerMixin as AsyncContextManagerMixin -from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin -from ._core._eventloop import current_time as current_time -from ._core._eventloop import get_all_backends as get_all_backends -from ._core._eventloop import get_available_backends as get_available_backends -from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class -from ._core._eventloop import run as run -from ._core._eventloop import sleep as sleep -from ._core._eventloop import sleep_forever as sleep_forever -from ._core._eventloop import sleep_until as sleep_until -from ._core._exceptions import BrokenResourceError as BrokenResourceError -from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter -from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess -from ._core._exceptions import BusyResourceError as BusyResourceError -from ._core._exceptions import ClosedResourceError as ClosedResourceError -from ._core._exceptions import ConnectionFailed as ConnectionFailed -from ._core._exceptions import DelimiterNotFound as DelimiterNotFound -from ._core._exceptions import EndOfStream as EndOfStream -from ._core._exceptions import IncompleteRead as IncompleteRead -from ._core._exceptions import NoEventLoopError as NoEventLoopError -from ._core._exceptions import RunFinishedError as RunFinishedError -from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError -from ._core._exceptions import WouldBlock as WouldBlock -from ._core._fileio import AsyncFile as AsyncFile -from ._core._fileio import Path as Path -from ._core._fileio import open_file as open_file -from ._core._fileio import wrap_file as wrap_file -from ._core._resources import aclose_forcefully as aclose_forcefully -from ._core._signals import open_signal_receiver as open_signal_receiver -from ._core._sockets import TCPConnectable as TCPConnectable -from ._core._sockets import UNIXConnectable as UNIXConnectable -from ._core._sockets import as_connectable as as_connectable -from ._core._sockets import connect_tcp as connect_tcp -from ._core._sockets import connect_unix as connect_unix -from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket -from ._core._sockets import ( - create_connected_unix_datagram_socket as create_connected_unix_datagram_socket, -) -from ._core._sockets import create_tcp_listener as create_tcp_listener -from ._core._sockets import create_udp_socket as create_udp_socket -from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket -from ._core._sockets import create_unix_listener as create_unix_listener -from ._core._sockets import getaddrinfo as getaddrinfo -from ._core._sockets import getnameinfo as getnameinfo -from ._core._sockets import notify_closing as notify_closing -from ._core._sockets import wait_readable as wait_readable -from ._core._sockets import wait_socket_readable as wait_socket_readable -from ._core._sockets import wait_socket_writable as wait_socket_writable -from ._core._sockets import wait_writable as wait_writable -from ._core._streams import create_memory_object_stream as create_memory_object_stream -from ._core._subprocesses import open_process as open_process -from ._core._subprocesses import run_process as run_process -from ._core._synchronization import CapacityLimiter as CapacityLimiter -from ._core._synchronization import ( - CapacityLimiterStatistics as CapacityLimiterStatistics, -) -from ._core._synchronization import Condition as Condition -from ._core._synchronization import ConditionStatistics as ConditionStatistics -from ._core._synchronization import Event as Event -from ._core._synchronization import EventStatistics as EventStatistics -from ._core._synchronization import Lock as Lock -from ._core._synchronization import LockStatistics as LockStatistics -from ._core._synchronization import ResourceGuard as ResourceGuard -from ._core._synchronization import Semaphore as Semaphore -from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics -from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED -from ._core._tasks import CancelScope as CancelScope -from ._core._tasks import create_task_group as create_task_group -from ._core._tasks import current_effective_deadline as current_effective_deadline -from ._core._tasks import fail_after as fail_after -from ._core._tasks import move_on_after as move_on_after -from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile -from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile -from ._core._tempfile import TemporaryDirectory as TemporaryDirectory -from ._core._tempfile import TemporaryFile as TemporaryFile -from ._core._tempfile import gettempdir as gettempdir -from ._core._tempfile import gettempdirb as gettempdirb -from ._core._tempfile import mkdtemp as mkdtemp -from ._core._tempfile import mkstemp as mkstemp -from ._core._testing import TaskInfo as TaskInfo -from ._core._testing import get_current_task as get_current_task -from ._core._testing import get_running_tasks as get_running_tasks -from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked -from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider -from ._core._typedattr import TypedAttributeSet as TypedAttributeSet -from ._core._typedattr import typed_attribute as typed_attribute - -# Re-export imports so they look like they live directly in this package -for __value in list(locals().values()): - if getattr(__value, "__module__", "").startswith("anyio."): - __value.__module__ = __name__ - - -del __value - - -def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]: - """Support deprecated aliases.""" - if attr == "BrokenWorkerIntepreter": - import warnings - - warnings.warn( - "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.", - DeprecationWarning, - stacklevel=2, - ) - return BrokenWorkerInterpreter - - raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 8cf42319a6bdae049506c35793a77fa87c9a3448..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/from_thread.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/from_thread.cpython-310.pyc deleted file mode 100644 index f29423d33365a25a2a6b0f70b8bcb1fde39af61f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/from_thread.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/functools.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/functools.cpython-310.pyc deleted file mode 100644 index 71a83106dde8bb11711e4209cacb7f18e6cbe57d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/functools.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/lowlevel.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/lowlevel.cpython-310.pyc deleted file mode 100644 index faa84d4b9556b7f6f85cba315fa0a34296ad047c..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/lowlevel.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/pytest_plugin.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/pytest_plugin.cpython-310.pyc deleted file mode 100644 index cae4c6eef2c6c582c421fb995b292d44a2cc9909..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/pytest_plugin.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/to_interpreter.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/to_interpreter.cpython-310.pyc deleted file mode 100644 index 7ff37a5fe42597df6dd47c7347dec7b05aa15ab1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/to_interpreter.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/to_process.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/to_process.cpython-310.pyc deleted file mode 100644 index e6c8870f094e6fd977b93bed31b97764a9ecdb0e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/to_process.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/__pycache__/to_thread.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/__pycache__/to_thread.cpython-310.pyc deleted file mode 100644 index d42e2bc6342fdded7a8ad0223e765cffb4b13af0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/__pycache__/to_thread.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_backends/__init__.py b/venv/lib/python3.10/site-packages/anyio/_backends/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 70169e9f68c4d402a8545658076ed2f1c4b62eac..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-310.pyc deleted file mode 100644 index 0faacfc042c01acece28ee729228b42de3fb4a31..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_trio.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_trio.cpython-310.pyc deleted file mode 100644 index fab64c6f79d5fc2568fb47435088581d5c4dc9d1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_trio.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_backends/_asyncio.py b/venv/lib/python3.10/site-packages/anyio/_backends/_asyncio.py deleted file mode 100644 index 8ff009e2699a3731e9b42e3318b87ef72f90900c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_backends/_asyncio.py +++ /dev/null @@ -1,2980 +0,0 @@ -from __future__ import annotations - -import array -import asyncio -import concurrent.futures -import contextvars -import math -import os -import socket -import sys -import threading -import weakref -from asyncio import ( - AbstractEventLoop, - CancelledError, - all_tasks, - create_task, - current_task, - get_running_loop, - sleep, -) -from asyncio.base_events import _run_until_complete_cb # type: ignore[attr-defined] -from collections import OrderedDict, deque -from collections.abc import ( - AsyncGenerator, - AsyncIterator, - Awaitable, - Callable, - Collection, - Coroutine, - Iterable, - Sequence, -) -from concurrent.futures import Future -from contextlib import AbstractContextManager, suppress -from contextvars import Context, copy_context -from dataclasses import dataclass, field -from functools import partial, wraps -from inspect import ( - CORO_RUNNING, - CORO_SUSPENDED, - getcoroutinestate, - iscoroutine, -) -from io import IOBase -from os import PathLike -from queue import Queue -from signal import Signals -from socket import AddressFamily, SocketKind -from threading import Thread -from types import CodeType, TracebackType -from typing import ( - IO, - TYPE_CHECKING, - Any, - Optional, - TypeVar, - cast, -) -from weakref import WeakKeyDictionary - -from .. import ( - CapacityLimiterStatistics, - EventStatistics, - LockStatistics, - TaskInfo, - abc, -) -from .._core._eventloop import ( - claim_worker_thread, - set_current_async_library, - threadlocals, -) -from .._core._exceptions import ( - BrokenResourceError, - BusyResourceError, - ClosedResourceError, - EndOfStream, - RunFinishedError, - WouldBlock, - iterate_exceptions, -) -from .._core._sockets import convert_ipv6_sockaddr -from .._core._streams import create_memory_object_stream -from .._core._synchronization import ( - CapacityLimiter as BaseCapacityLimiter, -) -from .._core._synchronization import Event as BaseEvent -from .._core._synchronization import Lock as BaseLock -from .._core._synchronization import ( - ResourceGuard, - SemaphoreStatistics, -) -from .._core._synchronization import Semaphore as BaseSemaphore -from .._core._tasks import CancelScope as BaseCancelScope -from ..abc import ( - AsyncBackend, - IPSockAddrType, - SocketListener, - UDPPacketType, - UNIXDatagramPacketType, -) -from ..abc._eventloop import StrOrBytesPath -from ..lowlevel import RunVar -from ..streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike -else: - FileDescriptorLike = object - -if sys.version_info >= (3, 10): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec - -if sys.version_info >= (3, 11): - from asyncio import Runner - from typing import TypeVarTuple, Unpack -else: - import contextvars - import enum - import signal - from asyncio import coroutines, events, exceptions, tasks - - from exceptiongroup import BaseExceptionGroup - from typing_extensions import TypeVarTuple, Unpack - - class _State(enum.Enum): - CREATED = "created" - INITIALIZED = "initialized" - CLOSED = "closed" - - class Runner: - # Copied from CPython 3.11 - def __init__( - self, - *, - debug: bool | None = None, - loop_factory: Callable[[], AbstractEventLoop] | None = None, - ): - self._state = _State.CREATED - self._debug = debug - self._loop_factory = loop_factory - self._loop: AbstractEventLoop | None = None - self._context = None - self._interrupt_count = 0 - self._set_event_loop = False - - def __enter__(self) -> Runner: - self._lazy_init() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """Shutdown and close event loop.""" - loop = self._loop - if self._state is not _State.INITIALIZED or loop is None: - return - try: - _cancel_all_tasks(loop) - loop.run_until_complete(loop.shutdown_asyncgens()) - if hasattr(loop, "shutdown_default_executor"): - loop.run_until_complete(loop.shutdown_default_executor()) - else: - loop.run_until_complete(_shutdown_default_executor(loop)) - finally: - if self._set_event_loop: - events.set_event_loop(None) - loop.close() - self._loop = None - self._state = _State.CLOSED - - def get_loop(self) -> AbstractEventLoop: - """Return embedded event loop.""" - self._lazy_init() - return self._loop - - def run(self, coro: Coroutine[T_Retval], *, context=None) -> T_Retval: - """Run a coroutine inside the embedded event loop.""" - if not coroutines.iscoroutine(coro): - raise ValueError(f"a coroutine was expected, got {coro!r}") - - if events._get_running_loop() is not None: - # fail fast with short traceback - raise RuntimeError( - "Runner.run() cannot be called from a running event loop" - ) - - self._lazy_init() - - if context is None: - context = self._context - task = context.run(self._loop.create_task, coro) - - if ( - threading.current_thread() is threading.main_thread() - and signal.getsignal(signal.SIGINT) is signal.default_int_handler - ): - sigint_handler = partial(self._on_sigint, main_task=task) - try: - signal.signal(signal.SIGINT, sigint_handler) - except ValueError: - # `signal.signal` may throw if `threading.main_thread` does - # not support signals (e.g. embedded interpreter with signals - # not registered - see gh-91880) - sigint_handler = None - else: - sigint_handler = None - - self._interrupt_count = 0 - try: - return self._loop.run_until_complete(task) - except exceptions.CancelledError: - if self._interrupt_count > 0: - uncancel = getattr(task, "uncancel", None) - if uncancel is not None and uncancel() == 0: - raise KeyboardInterrupt # noqa: B904 - raise # CancelledError - finally: - if ( - sigint_handler is not None - and signal.getsignal(signal.SIGINT) is sigint_handler - ): - signal.signal(signal.SIGINT, signal.default_int_handler) - - def _lazy_init(self) -> None: - if self._state is _State.CLOSED: - raise RuntimeError("Runner is closed") - if self._state is _State.INITIALIZED: - return - if self._loop_factory is None: - self._loop = events.new_event_loop() - if not self._set_event_loop: - # Call set_event_loop only once to avoid calling - # attach_loop multiple times on child watchers - events.set_event_loop(self._loop) - self._set_event_loop = True - else: - self._loop = self._loop_factory() - if self._debug is not None: - self._loop.set_debug(self._debug) - self._context = contextvars.copy_context() - self._state = _State.INITIALIZED - - def _on_sigint(self, signum, frame, main_task: asyncio.Task) -> None: - self._interrupt_count += 1 - if self._interrupt_count == 1 and not main_task.done(): - main_task.cancel() - # wakeup loop if it is blocked by select() with long timeout - self._loop.call_soon_threadsafe(lambda: None) - return - raise KeyboardInterrupt() - - def _cancel_all_tasks(loop: AbstractEventLoop) -> None: - to_cancel = tasks.all_tasks(loop) - if not to_cancel: - return - - for task in to_cancel: - task.cancel() - - loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True)) - - for task in to_cancel: - if task.cancelled(): - continue - if task.exception() is not None: - loop.call_exception_handler( - { - "message": "unhandled exception during asyncio.run() shutdown", - "exception": task.exception(), - "task": task, - } - ) - - async def _shutdown_default_executor(loop: AbstractEventLoop) -> None: - """Schedule the shutdown of the default executor.""" - - def _do_shutdown(future: asyncio.futures.Future) -> None: - try: - loop._default_executor.shutdown(wait=True) # type: ignore[attr-defined] - loop.call_soon_threadsafe(future.set_result, None) - except Exception as ex: - loop.call_soon_threadsafe(future.set_exception, ex) - - loop._executor_shutdown_called = True - if loop._default_executor is None: - return - future = loop.create_future() - thread = threading.Thread(target=_do_shutdown, args=(future,)) - thread.start() - try: - await future - finally: - thread.join() - - -T_Retval = TypeVar("T_Retval") -T_contra = TypeVar("T_contra", contravariant=True) -PosArgsT = TypeVarTuple("PosArgsT") -P = ParamSpec("P") - -_root_task: RunVar[asyncio.Task | None] = RunVar("_root_task") - - -def find_root_task() -> asyncio.Task: - root_task = _root_task.get(None) - if root_task is not None and not root_task.done(): - return root_task - - # Look for a task that has been started via run_until_complete() - for task in all_tasks(): - if task._callbacks and not task.done(): - callbacks = [cb for cb, context in task._callbacks] - for cb in callbacks: - if ( - cb is _run_until_complete_cb - or getattr(cb, "__module__", None) == "uvloop.loop" - ): - _root_task.set(task) - return task - - # Look up the topmost task in the AnyIO task tree, if possible - task = cast(asyncio.Task, current_task()) - state = _task_states.get(task) - if state: - cancel_scope = state.cancel_scope - while cancel_scope and cancel_scope._parent_scope is not None: - cancel_scope = cancel_scope._parent_scope - - if cancel_scope is not None: - return cast(asyncio.Task, cancel_scope._host_task) - - return task - - -def get_callable_name(func: Callable) -> str: - module = getattr(func, "__module__", None) - qualname = getattr(func, "__qualname__", None) - return ".".join([x for x in (module, qualname) if x]) - - -# -# Event loop -# - -_run_vars: WeakKeyDictionary[asyncio.AbstractEventLoop, Any] = WeakKeyDictionary() - - -def _task_started(task: asyncio.Task) -> bool: - """Return ``True`` if the task has been started and has not finished.""" - # The task coro should never be None here, as we never add finished tasks to the - # task list - coro = task.get_coro() - assert coro is not None - try: - return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED) - except AttributeError: - # task coro is async_genenerator_asend https://bugs.python.org/issue37771 - raise Exception(f"Cannot determine if task {task} has started or not") from None - - -# -# Timeouts and cancellation -# - - -def is_anyio_cancellation(exc: CancelledError) -> bool: - # Sometimes third party frameworks catch a CancelledError and raise a new one, so as - # a workaround we have to look at the previous ones in __context__ too for a - # matching cancel message - while True: - if ( - exc.args - and isinstance(exc.args[0], str) - and exc.args[0].startswith("Cancelled via cancel scope ") - ): - return True - - if isinstance(exc.__context__, CancelledError): - exc = exc.__context__ - continue - - return False - - -class CancelScope(BaseCancelScope): - def __new__( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return object.__new__(cls) - - def __init__(self, deadline: float = math.inf, shield: bool = False): - self._deadline = deadline - self._shield = shield - self._parent_scope: CancelScope | None = None - self._child_scopes: set[CancelScope] = set() - self._cancel_called = False - self._cancel_reason: str | None = None - self._cancelled_caught = False - self._active = False - self._timeout_handle: asyncio.TimerHandle | None = None - self._cancel_handle: asyncio.Handle | None = None - self._tasks: set[asyncio.Task] = set() - self._host_task: asyncio.Task | None = None - if sys.version_info >= (3, 11): - self._pending_uncancellations: int | None = 0 - else: - self._pending_uncancellations = None - - def __enter__(self) -> CancelScope: - if self._active: - raise RuntimeError( - "Each CancelScope may only be used for a single 'with' block" - ) - - self._host_task = host_task = cast(asyncio.Task, current_task()) - self._tasks.add(host_task) - try: - task_state = _task_states[host_task] - except KeyError: - task_state = TaskState(None, self) - _task_states[host_task] = task_state - else: - self._parent_scope = task_state.cancel_scope - task_state.cancel_scope = self - if self._parent_scope is not None: - # If using an eager task factory, the parent scope may not even contain - # the host task - self._parent_scope._child_scopes.add(self) - self._parent_scope._tasks.discard(host_task) - - self._timeout() - self._active = True - - # Start cancelling the host task if the scope was cancelled before entering - if self._cancel_called: - self._deliver_cancellation(self) - - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - del exc_tb - - if not self._active: - raise RuntimeError("This cancel scope is not active") - if current_task() is not self._host_task: - raise RuntimeError( - "Attempted to exit cancel scope in a different task than it was " - "entered in" - ) - - assert self._host_task is not None - host_task_state = _task_states.get(self._host_task) - if host_task_state is None or host_task_state.cancel_scope is not self: - raise RuntimeError( - "Attempted to exit a cancel scope that isn't the current tasks's " - "current cancel scope" - ) - - try: - self._active = False - if self._timeout_handle: - self._timeout_handle.cancel() - self._timeout_handle = None - - self._tasks.remove(self._host_task) - if self._parent_scope is not None: - self._parent_scope._child_scopes.remove(self) - self._parent_scope._tasks.add(self._host_task) - - host_task_state.cancel_scope = self._parent_scope - - # Restart the cancellation effort in the closest visible, cancelled parent - # scope if necessary - self._restart_cancellation_in_parent() - - # We only swallow the exception iff it was an AnyIO CancelledError, either - # directly as exc_val or inside an exception group and there are no cancelled - # parent cancel scopes visible to us here - if self._cancel_called and not self._parent_cancellation_is_visible_to_us: - # For each level-cancel() call made on the host task, call uncancel() - while self._pending_uncancellations: - self._host_task.uncancel() - self._pending_uncancellations -= 1 - - # Update cancelled_caught and check for exceptions we must not swallow - cannot_swallow_exc_val = False - if exc_val is not None: - for exc in iterate_exceptions(exc_val): - if isinstance(exc, CancelledError) and is_anyio_cancellation( - exc - ): - self._cancelled_caught = True - else: - cannot_swallow_exc_val = True - - return self._cancelled_caught and not cannot_swallow_exc_val - else: - if self._pending_uncancellations: - assert self._parent_scope is not None - assert self._parent_scope._pending_uncancellations is not None - self._parent_scope._pending_uncancellations += ( - self._pending_uncancellations - ) - self._pending_uncancellations = 0 - - return False - finally: - self._host_task = None - del exc_val - - @property - def _effectively_cancelled(self) -> bool: - cancel_scope: CancelScope | None = self - while cancel_scope is not None: - if cancel_scope._cancel_called: - return True - - if cancel_scope.shield: - return False - - cancel_scope = cancel_scope._parent_scope - - return False - - @property - def _parent_cancellation_is_visible_to_us(self) -> bool: - return ( - self._parent_scope is not None - and not self.shield - and self._parent_scope._effectively_cancelled - ) - - def _timeout(self) -> None: - if self._deadline != math.inf: - loop = get_running_loop() - if loop.time() >= self._deadline: - self.cancel("deadline exceeded") - else: - self._timeout_handle = loop.call_at(self._deadline, self._timeout) - - def _deliver_cancellation(self, origin: CancelScope) -> bool: - """ - Deliver cancellation to directly contained tasks and nested cancel scopes. - - Schedule another run at the end if we still have tasks eligible for - cancellation. - - :param origin: the cancel scope that originated the cancellation - :return: ``True`` if the delivery needs to be retried on the next cycle - - """ - should_retry = False - current = current_task() - for task in self._tasks: - should_retry = True - if task._must_cancel: # type: ignore[attr-defined] - continue - - # The task is eligible for cancellation if it has started - if task is not current and (task is self._host_task or _task_started(task)): - waiter = task._fut_waiter # type: ignore[attr-defined] - if not isinstance(waiter, asyncio.Future) or not waiter.done(): - task.cancel(origin._cancel_reason) - if ( - task is origin._host_task - and origin._pending_uncancellations is not None - ): - origin._pending_uncancellations += 1 - - # Deliver cancellation to child scopes that aren't shielded or running their own - # cancellation callbacks - for scope in self._child_scopes: - if not scope._shield and not scope.cancel_called: - should_retry = scope._deliver_cancellation(origin) or should_retry - - # Schedule another callback if there are still tasks left - if origin is self: - if should_retry: - self._cancel_handle = get_running_loop().call_soon( - self._deliver_cancellation, origin - ) - else: - self._cancel_handle = None - - return should_retry - - def _restart_cancellation_in_parent(self) -> None: - """ - Restart the cancellation effort in the closest directly cancelled parent scope. - - """ - scope = self._parent_scope - while scope is not None: - if scope._cancel_called: - if scope._cancel_handle is None: - scope._deliver_cancellation(scope) - - break - - # No point in looking beyond any shielded scope - if scope._shield: - break - - scope = scope._parent_scope - - def cancel(self, reason: str | None = None) -> None: - if not self._cancel_called: - if self._timeout_handle: - self._timeout_handle.cancel() - self._timeout_handle = None - - self._cancel_called = True - self._cancel_reason = f"Cancelled via cancel scope {id(self):x}" - if task := current_task(): - self._cancel_reason += f" by {task}" - - if reason: - self._cancel_reason += f"; reason: {reason}" - - if self._host_task is not None: - self._deliver_cancellation(self) - - @property - def deadline(self) -> float: - return self._deadline - - @deadline.setter - def deadline(self, value: float) -> None: - self._deadline = float(value) - if self._timeout_handle is not None: - self._timeout_handle.cancel() - self._timeout_handle = None - - if self._active and not self._cancel_called: - self._timeout() - - @property - def cancel_called(self) -> bool: - return self._cancel_called - - @property - def cancelled_caught(self) -> bool: - return self._cancelled_caught - - @property - def shield(self) -> bool: - return self._shield - - @shield.setter - def shield(self, value: bool) -> None: - if self._shield != value: - self._shield = value - if not value: - self._restart_cancellation_in_parent() - - -# -# Task states -# - - -class TaskState: - """ - Encapsulates auxiliary task information that cannot be added to the Task instance - itself because there are no guarantees about its implementation. - """ - - __slots__ = "parent_id", "cancel_scope", "__weakref__" - - def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None): - self.parent_id = parent_id - self.cancel_scope = cancel_scope - - -_task_states: WeakKeyDictionary[asyncio.Task, TaskState] = WeakKeyDictionary() - - -# -# Task groups -# - - -class _AsyncioTaskStatus(abc.TaskStatus): - def __init__(self, future: asyncio.Future, parent_id: int): - self._future = future - self._parent_id = parent_id - - def started(self, value: T_contra | None = None) -> None: - try: - self._future.set_result(value) - except asyncio.InvalidStateError: - if not self._future.cancelled(): - raise RuntimeError( - "called 'started' twice on the same task status" - ) from None - - task = cast(asyncio.Task, current_task()) - _task_states[task].parent_id = self._parent_id - - -if sys.version_info >= (3, 12): - _eager_task_factory_code: CodeType | None = asyncio.eager_task_factory.__code__ -else: - _eager_task_factory_code = None - - -class TaskGroup(abc.TaskGroup): - def __init__(self) -> None: - self.cancel_scope: CancelScope = CancelScope() - self._active = False - self._exceptions: list[BaseException] = [] - self._tasks: set[asyncio.Task] = set() - self._on_completed_fut: asyncio.Future[None] | None = None - - async def __aenter__(self) -> TaskGroup: - self.cancel_scope.__enter__() - self._active = True - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - try: - if exc_val is not None: - self.cancel_scope.cancel() - if not isinstance(exc_val, CancelledError): - self._exceptions.append(exc_val) - - loop = get_running_loop() - try: - if self._tasks: - with CancelScope() as wait_scope: - while self._tasks: - self._on_completed_fut = loop.create_future() - - try: - await self._on_completed_fut - except CancelledError as exc: - # Shield the scope against further cancellation attempts, - # as they're not productive (#695) - wait_scope.shield = True - self.cancel_scope.cancel() - - # Set exc_val from the cancellation exception if it was - # previously unset. However, we should not replace a native - # cancellation exception with one raise by a cancel scope. - if exc_val is None or ( - isinstance(exc_val, CancelledError) - and not is_anyio_cancellation(exc) - ): - exc_val = exc - - self._on_completed_fut = None - else: - # If there are no child tasks to wait on, run at least one checkpoint - # anyway - await AsyncIOBackend.cancel_shielded_checkpoint() - - self._active = False - if self._exceptions: - # The exception that got us here should already have been - # added to self._exceptions so it's ok to break exception - # chaining and avoid adding a "During handling of above..." - # for each nesting level. - raise BaseExceptionGroup( - "unhandled errors in a TaskGroup", self._exceptions - ) from None - elif exc_val: - raise exc_val - except BaseException as exc: - if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__): - return True - - raise - - return self.cancel_scope.__exit__(exc_type, exc_val, exc_tb) - finally: - del exc_val, exc_tb, self._exceptions - - def _spawn( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - args: tuple[Unpack[PosArgsT]], - name: object, - task_status_future: asyncio.Future | None = None, - ) -> asyncio.Task: - def task_done(_task: asyncio.Task) -> None: - if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: - asyncio.future_discard_from_awaited_by( - _task, self.cancel_scope._host_task - ) - - task_state = _task_states[_task] - assert task_state.cancel_scope is not None - assert _task in task_state.cancel_scope._tasks - task_state.cancel_scope._tasks.remove(_task) - self._tasks.remove(task) - del _task_states[_task] - - if self._on_completed_fut is not None and not self._tasks: - try: - self._on_completed_fut.set_result(None) - except asyncio.InvalidStateError: - pass - - try: - exc = _task.exception() - except CancelledError as e: - while isinstance(e.__context__, CancelledError): - e = e.__context__ - - exc = e - - if exc is not None: - # The future can only be in the cancelled state if the host task was - # cancelled, so return immediately instead of adding one more - # CancelledError to the exceptions list - if task_status_future is not None and task_status_future.cancelled(): - return - - if task_status_future is None or task_status_future.done(): - if not isinstance(exc, CancelledError): - self._exceptions.append(exc) - - if not self.cancel_scope._effectively_cancelled: - self.cancel_scope.cancel() - else: - task_status_future.set_exception(exc) - elif task_status_future is not None and not task_status_future.done(): - task_status_future.set_exception( - RuntimeError("Child exited without calling task_status.started()") - ) - - if not self._active: - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - kwargs = {} - if task_status_future: - parent_id = id(current_task()) - kwargs["task_status"] = _AsyncioTaskStatus( - task_status_future, id(self.cancel_scope._host_task) - ) - else: - parent_id = id(self.cancel_scope._host_task) - - coro = func(*args, **kwargs) - if not iscoroutine(coro): - prefix = f"{func.__module__}." if hasattr(func, "__module__") else "" - raise TypeError( - f"Expected {prefix}{func.__qualname__}() to return a coroutine, but " - f"the return value ({coro!r}) is not a coroutine object" - ) - - name = get_callable_name(func) if name is None else str(name) - loop = asyncio.get_running_loop() - if ( - (factory := loop.get_task_factory()) - and getattr(factory, "__code__", None) is _eager_task_factory_code - and (closure := getattr(factory, "__closure__", None)) - ): - custom_task_constructor = closure[0].cell_contents - task = custom_task_constructor(coro, loop=loop, name=name) - else: - task = create_task(coro, name=name) - - # Make the spawned task inherit the task group's cancel scope - _task_states[task] = TaskState( - parent_id=parent_id, cancel_scope=self.cancel_scope - ) - self.cancel_scope._tasks.add(task) - self._tasks.add(task) - if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: - asyncio.future_add_to_awaited_by(task, self.cancel_scope._host_task) - - task.add_done_callback(task_done) - return task - - def start_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> None: - self._spawn(func, args, name) - - async def start( - self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None - ) -> Any: - future: asyncio.Future = asyncio.Future() - task = self._spawn(func, args, name, future) - - # If the task raises an exception after sending a start value without a switch - # point between, the task group is cancelled and this method never proceeds to - # process the completed future. That's why we have to have a shielded cancel - # scope here. - try: - return await future - except CancelledError: - # Cancel the task and wait for it to exit before returning - task.cancel() - with CancelScope(shield=True), suppress(CancelledError): - await task - - raise - - -# -# Threads -# - -_Retval_Queue_Type = tuple[Optional[T_Retval], Optional[BaseException]] - - -class WorkerThread(Thread): - MAX_IDLE_TIME = 10 # seconds - - def __init__( - self, - root_task: asyncio.Task, - workers: set[WorkerThread], - idle_workers: deque[WorkerThread], - ): - super().__init__(name="AnyIO worker thread") - self.root_task = root_task - self.workers = workers - self.idle_workers = idle_workers - self.loop = root_task._loop - self.queue: Queue[ - tuple[Context, Callable, tuple, asyncio.Future, CancelScope] | None - ] = Queue(2) - self.idle_since = AsyncIOBackend.current_time() - self.stopping = False - - def _report_result( - self, future: asyncio.Future, result: Any, exc: BaseException | None - ) -> None: - self.idle_since = AsyncIOBackend.current_time() - if not self.stopping: - self.idle_workers.append(self) - - if not future.cancelled(): - if exc is not None: - if isinstance(exc, StopIteration): - new_exc = RuntimeError("coroutine raised StopIteration") - new_exc.__cause__ = exc - exc = new_exc - - future.set_exception(exc) - else: - future.set_result(result) - - def run(self) -> None: - with claim_worker_thread(AsyncIOBackend, self.loop): - while True: - item = self.queue.get() - if item is None: - # Shutdown command received - return - - context, func, args, future, cancel_scope = item - if not future.cancelled(): - result = None - exception: BaseException | None = None - threadlocals.current_cancel_scope = cancel_scope - try: - result = context.run(func, *args) - except BaseException as exc: - exception = exc - finally: - del threadlocals.current_cancel_scope - - if not self.loop.is_closed(): - self.loop.call_soon_threadsafe( - self._report_result, future, result, exception - ) - - del result, exception - - self.queue.task_done() - del item, context, func, args, future, cancel_scope - - def stop(self, f: asyncio.Task | None = None) -> None: - self.stopping = True - self.queue.put_nowait(None) - self.workers.discard(self) - try: - self.idle_workers.remove(self) - except ValueError: - pass - - -_threadpool_idle_workers: RunVar[deque[WorkerThread]] = RunVar( - "_threadpool_idle_workers" -) -_threadpool_workers: RunVar[set[WorkerThread]] = RunVar("_threadpool_workers") - - -# -# Subprocesses -# - - -@dataclass(eq=False) -class StreamReaderWrapper(abc.ByteReceiveStream): - _stream: asyncio.StreamReader - - async def receive(self, max_bytes: int = 65536) -> bytes: - data = await self._stream.read(max_bytes) - if data: - return data - else: - raise EndOfStream - - async def aclose(self) -> None: - self._stream.set_exception(ClosedResourceError()) - await AsyncIOBackend.checkpoint() - - -@dataclass(eq=False) -class StreamWriterWrapper(abc.ByteSendStream): - _stream: asyncio.StreamWriter - _closed: bool = field(init=False, default=False) - - async def send(self, item: bytes) -> None: - await AsyncIOBackend.checkpoint_if_cancelled() - stream_paused = self._stream._protocol._paused # type: ignore[attr-defined] - try: - self._stream.write(item) - await self._stream.drain() - except (ConnectionResetError, BrokenPipeError, RuntimeError) as exc: - # If closed by us and/or the peer: - # * on stdlib, drain() raises ConnectionResetError or BrokenPipeError - # * on uvloop and Winloop, write() eventually starts raising RuntimeError - if self._closed: - raise ClosedResourceError from exc - elif self._stream.is_closing(): - raise BrokenResourceError from exc - - raise - - if not stream_paused: - await AsyncIOBackend.cancel_shielded_checkpoint() - - async def aclose(self) -> None: - self._closed = True - self._stream.close() - await AsyncIOBackend.checkpoint() - - -@dataclass(eq=False) -class Process(abc.Process): - _process: asyncio.subprocess.Process - _stdin: StreamWriterWrapper | None - _stdout: StreamReaderWrapper | None - _stderr: StreamReaderWrapper | None - - async def aclose(self) -> None: - with CancelScope(shield=True) as scope: - if self._stdin: - await self._stdin.aclose() - if self._stdout: - await self._stdout.aclose() - if self._stderr: - await self._stderr.aclose() - - scope.shield = False - try: - await self.wait() - except BaseException: - scope.shield = True - self.kill() - await self.wait() - raise - - async def wait(self) -> int: - return await self._process.wait() - - def terminate(self) -> None: - self._process.terminate() - - def kill(self) -> None: - self._process.kill() - - def send_signal(self, signal: int) -> None: - self._process.send_signal(signal) - - @property - def pid(self) -> int: - return self._process.pid - - @property - def returncode(self) -> int | None: - return self._process.returncode - - @property - def stdin(self) -> abc.ByteSendStream | None: - return self._stdin - - @property - def stdout(self) -> abc.ByteReceiveStream | None: - return self._stdout - - @property - def stderr(self) -> abc.ByteReceiveStream | None: - return self._stderr - - -def _forcibly_shutdown_process_pool_on_exit( - workers: set[Process], _task: object -) -> None: - """ - Forcibly shuts down worker processes belonging to this event loop.""" - child_watcher: asyncio.AbstractChildWatcher | None = None # type: ignore[name-defined] - if sys.version_info < (3, 12): - try: - child_watcher = asyncio.get_event_loop_policy().get_child_watcher() - except NotImplementedError: - pass - - # Close as much as possible (w/o async/await) to avoid warnings - for process in workers.copy(): - if process.returncode is None: - continue - - process._stdin._stream._transport.close() # type: ignore[union-attr] - process._stdout._stream._transport.close() # type: ignore[union-attr] - process._stderr._stream._transport.close() # type: ignore[union-attr] - process.kill() - if child_watcher: - child_watcher.remove_child_handler(process.pid) - - -async def _shutdown_process_pool_on_exit(workers: set[abc.Process]) -> None: - """ - Shuts down worker processes belonging to this event loop. - - NOTE: this only works when the event loop was started using asyncio.run() or - anyio.run(). - - """ - process: abc.Process - try: - await sleep(math.inf) - except asyncio.CancelledError: - workers = workers.copy() - for process in workers: - if process.returncode is None: - process.kill() - - for process in workers: - await process.aclose() - - -# -# Sockets and networking -# - - -class StreamProtocol(asyncio.Protocol): - read_queue: deque[bytes] - read_event: asyncio.Event - write_event: asyncio.Event - exception: Exception | None = None - is_at_eof: bool = False - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - self.read_queue = deque() - self.read_event = asyncio.Event() - self.write_event = asyncio.Event() - self.write_event.set() - cast(asyncio.Transport, transport).set_write_buffer_limits(0) - - def connection_lost(self, exc: Exception | None) -> None: - if exc: - self.exception = BrokenResourceError() - self.exception.__cause__ = exc - - self.read_event.set() - self.write_event.set() - - def data_received(self, data: bytes) -> None: - # ProactorEventloop sometimes sends bytearray instead of bytes - self.read_queue.append(bytes(data)) - self.read_event.set() - - def eof_received(self) -> bool | None: - self.is_at_eof = True - self.read_event.set() - return True - - def pause_writing(self) -> None: - self.write_event = asyncio.Event() - - def resume_writing(self) -> None: - self.write_event.set() - - -class DatagramProtocol(asyncio.DatagramProtocol): - read_queue: deque[tuple[bytes, IPSockAddrType]] - read_event: asyncio.Event - write_event: asyncio.Event - exception: Exception | None = None - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - self.read_queue = deque(maxlen=100) # arbitrary value - self.read_event = asyncio.Event() - self.write_event = asyncio.Event() - self.write_event.set() - - def connection_lost(self, exc: Exception | None) -> None: - self.read_event.set() - self.write_event.set() - - def datagram_received(self, data: bytes, addr: IPSockAddrType) -> None: - addr = convert_ipv6_sockaddr(addr) - self.read_queue.append((data, addr)) - self.read_event.set() - - def error_received(self, exc: Exception) -> None: - self.exception = exc - - def pause_writing(self) -> None: - self.write_event.clear() - - def resume_writing(self) -> None: - self.write_event.set() - - -class SocketStream(abc.SocketStream): - def __init__(self, transport: asyncio.Transport, protocol: StreamProtocol): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def receive(self, max_bytes: int = 65536) -> bytes: - with self._receive_guard: - if ( - not self._protocol.read_event.is_set() - and not self._transport.is_closing() - and not self._protocol.is_at_eof - ): - self._transport.resume_reading() - await self._protocol.read_event.wait() - self._transport.pause_reading() - else: - await AsyncIOBackend.checkpoint() - - try: - chunk = self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - elif self._protocol.exception: - raise self._protocol.exception from None - else: - raise EndOfStream from None - - if len(chunk) > max_bytes: - # Split the oversized chunk - chunk, leftover = chunk[:max_bytes], chunk[max_bytes:] - self._protocol.read_queue.appendleft(leftover) - - # If the read queue is empty, clear the flag so that the next call will - # block until data is available - if not self._protocol.read_queue: - self._protocol.read_event.clear() - - return chunk - - async def send(self, item: bytes) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - - if self._closed: - raise ClosedResourceError - elif self._protocol.exception is not None: - raise self._protocol.exception - - try: - self._transport.write(item) - except RuntimeError as exc: - if self._transport.is_closing(): - raise BrokenResourceError from exc - else: - raise - - await self._protocol.write_event.wait() - - async def send_eof(self) -> None: - try: - self._transport.write_eof() - except OSError: - pass - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - try: - self._transport.write_eof() - except OSError: - pass - - self._transport.close() - await sleep(0) - self._transport.abort() - - -class _RawSocketMixin: - _receive_future: asyncio.Future | None = None - _send_future: asyncio.Future | None = None - _closing = False - - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - def _wait_until_readable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: - def callback(f: object) -> None: - del self._receive_future - loop.remove_reader(self.__raw_socket) - - f = self._receive_future = asyncio.Future() - loop.add_reader(self.__raw_socket, f.set_result, None) - f.add_done_callback(callback) - return f - - def _wait_until_writable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: - def callback(f: object) -> None: - del self._send_future - loop.remove_writer(self.__raw_socket) - - f = self._send_future = asyncio.Future() - loop.add_writer(self.__raw_socket, f.set_result, None) - f.add_done_callback(callback) - return f - - async def aclose(self) -> None: - if not self._closing: - self._closing = True - if self.__raw_socket.fileno() != -1: - self.__raw_socket.close() - - if self._receive_future: - self._receive_future.set_result(None) - if self._send_future: - self._send_future.set_result(None) - - -class UNIXSocketStream(_RawSocketMixin, abc.UNIXSocketStream): - async def send_eof(self) -> None: - with self._send_guard: - self._raw_socket.shutdown(socket.SHUT_WR) - - async def receive(self, max_bytes: int = 65536) -> bytes: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recv(max_bytes) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - if not data: - raise EndOfStream - - return data - - async def send(self, item: bytes) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - view = memoryview(item) - while view: - try: - bytes_sent = self._raw_socket.send(view) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - view = view[bytes_sent:] - - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - if not isinstance(msglen, int) or msglen < 0: - raise ValueError("msglen must be a non-negative integer") - if not isinstance(maxfds, int) or maxfds < 1: - raise ValueError("maxfds must be a positive integer") - - loop = get_running_loop() - fds = array.array("i") - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - message, ancdata, flags, addr = self._raw_socket.recvmsg( - msglen, socket.CMSG_LEN(maxfds * fds.itemsize) - ) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - if not message and not ancdata: - raise EndOfStream - - break - - for cmsg_level, cmsg_type, cmsg_data in ancdata: - if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: - raise RuntimeError( - f"Received unexpected ancillary data; message = {message!r}, " - f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" - ) - - fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) - - return message, list(fds) - - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - if not message: - raise ValueError("message must not be empty") - if not fds: - raise ValueError("fds must not be empty") - - loop = get_running_loop() - filenos: list[int] = [] - for fd in fds: - if isinstance(fd, int): - filenos.append(fd) - elif isinstance(fd, IOBase): - filenos.append(fd.fileno()) - - fdarray = array.array("i", filenos) - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - # The ignore can be removed after mypy picks up - # https://github.com/python/typeshed/pull/5545 - self._raw_socket.sendmsg( - [message], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fdarray)] - ) - break - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - - -class TCPSocketListener(abc.SocketListener): - _accept_scope: CancelScope | None = None - _closed = False - - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._loop = cast(asyncio.BaseEventLoop, get_running_loop()) - self._accept_guard = ResourceGuard("accepting connections from") - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - async def accept(self) -> abc.SocketStream: - if self._closed: - raise ClosedResourceError - - with self._accept_guard: - await AsyncIOBackend.checkpoint() - with CancelScope() as self._accept_scope: - try: - client_sock, _addr = await self._loop.sock_accept(self._raw_socket) - except asyncio.CancelledError: - # Workaround for https://bugs.python.org/issue41317 - try: - self._loop.remove_reader(self._raw_socket) - except (ValueError, NotImplementedError): - pass - - if self._closed: - raise ClosedResourceError from None - - raise - finally: - self._accept_scope = None - - client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - transport, protocol = await self._loop.connect_accepted_socket( - StreamProtocol, client_sock - ) - return SocketStream(transport, protocol) - - async def aclose(self) -> None: - if self._closed: - return - - self._closed = True - if self._accept_scope: - # Workaround for https://bugs.python.org/issue41317 - try: - self._loop.remove_reader(self._raw_socket) - except (ValueError, NotImplementedError): - pass - - self._accept_scope.cancel() - await sleep(0) - - self._raw_socket.close() - - -class UNIXSocketListener(abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._loop = get_running_loop() - self._accept_guard = ResourceGuard("accepting connections from") - self._closed = False - - async def accept(self) -> abc.SocketStream: - await AsyncIOBackend.checkpoint() - with self._accept_guard: - while True: - try: - client_sock, _ = self.__raw_socket.accept() - client_sock.setblocking(False) - return UNIXSocketStream(client_sock) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - self._loop.add_reader(self.__raw_socket, f.set_result, None) - f.add_done_callback( - lambda _: self._loop.remove_reader(self.__raw_socket) - ) - await f - except OSError as exc: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - - async def aclose(self) -> None: - self._closed = True - self.__raw_socket.close() - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - -class UDPSocket(abc.UDPSocket): - def __init__( - self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol - ): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - self._transport.close() - - async def receive(self) -> tuple[bytes, IPSockAddrType]: - with self._receive_guard: - await AsyncIOBackend.checkpoint() - - # If the buffer is empty, ask for more data - if not self._protocol.read_queue and not self._transport.is_closing(): - self._protocol.read_event.clear() - await self._protocol.read_event.wait() - - try: - return self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from None - - async def send(self, item: UDPPacketType) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - await self._protocol.write_event.wait() - if self._closed: - raise ClosedResourceError - elif self._transport.is_closing(): - raise BrokenResourceError - else: - self._transport.sendto(*item) - - -class ConnectedUDPSocket(abc.ConnectedUDPSocket): - def __init__( - self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol - ): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - self._transport.close() - - async def receive(self) -> bytes: - with self._receive_guard: - await AsyncIOBackend.checkpoint() - - # If the buffer is empty, ask for more data - if not self._protocol.read_queue and not self._transport.is_closing(): - self._protocol.read_event.clear() - await self._protocol.read_event.wait() - - try: - packet = self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from None - - return packet[0] - - async def send(self, item: bytes) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - await self._protocol.write_event.wait() - if self._closed: - raise ClosedResourceError - elif self._transport.is_closing(): - raise BrokenResourceError - else: - self._transport.sendto(item) - - -class UNIXDatagramSocket(_RawSocketMixin, abc.UNIXDatagramSocket): - async def receive(self) -> UNIXDatagramPacketType: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recvfrom(65536) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return data - - async def send(self, item: UNIXDatagramPacketType) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - self._raw_socket.sendto(*item) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return - - -class ConnectedUNIXDatagramSocket(_RawSocketMixin, abc.ConnectedUNIXDatagramSocket): - async def receive(self) -> bytes: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recv(65536) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return data - - async def send(self, item: bytes) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - self._raw_socket.send(item) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return - - -_read_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("read_events") -_write_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("write_events") - - -# -# Synchronization -# - - -class Event(BaseEvent): - def __new__(cls) -> Event: - return object.__new__(cls) - - def __init__(self) -> None: - self._event = asyncio.Event() - - def set(self) -> None: - self._event.set() - - def is_set(self) -> bool: - return self._event.is_set() - - async def wait(self) -> None: - if self.is_set(): - await AsyncIOBackend.checkpoint() - else: - await self._event.wait() - - def statistics(self) -> EventStatistics: - return EventStatistics(len(self._event._waiters)) - - -class Lock(BaseLock): - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False) -> None: - self._fast_acquire = fast_acquire - self._owner_task: asyncio.Task | None = None - self._waiters: deque[tuple[asyncio.Task, asyncio.Future]] = deque() - - async def acquire(self) -> None: - task = cast(asyncio.Task, current_task()) - if self._owner_task is None and not self._waiters: - await AsyncIOBackend.checkpoint_if_cancelled() - self._owner_task = task - - # Unless on the "fast path", yield control of the event loop so that other - # tasks can run too - if not self._fast_acquire: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except CancelledError: - self.release() - raise - - return - - if self._owner_task == task: - raise RuntimeError("Attempted to acquire an already held Lock") - - fut: asyncio.Future[None] = asyncio.Future() - item = task, fut - self._waiters.append(item) - try: - await fut - except CancelledError: - self._waiters.remove(item) - if self._owner_task is task: - self.release() - - raise - - self._waiters.remove(item) - - def acquire_nowait(self) -> None: - task = cast(asyncio.Task, current_task()) - if self._owner_task is None and not self._waiters: - self._owner_task = task - return - - if self._owner_task is task: - raise RuntimeError("Attempted to acquire an already held Lock") - - raise WouldBlock - - def locked(self) -> bool: - return self._owner_task is not None - - def release(self) -> None: - if self._owner_task != current_task(): - raise RuntimeError("The current task is not holding this lock") - - for task, fut in self._waiters: - if not fut.cancelled(): - self._owner_task = task - fut.set_result(None) - return - - self._owner_task = None - - def statistics(self) -> LockStatistics: - task_info = AsyncIOTaskInfo(self._owner_task) if self._owner_task else None - return LockStatistics(self.locked(), task_info, len(self._waiters)) - - -class Semaphore(BaseSemaphore): - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ): - super().__init__(initial_value, max_value=max_value) - self._value = initial_value - self._max_value = max_value - self._fast_acquire = fast_acquire - self._waiters: deque[asyncio.Future[None]] = deque() - - async def acquire(self) -> None: - if self._value > 0 and not self._waiters: - await AsyncIOBackend.checkpoint_if_cancelled() - self._value -= 1 - - # Unless on the "fast path", yield control of the event loop so that other - # tasks can run too - if not self._fast_acquire: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except CancelledError: - self.release() - raise - - return - - fut: asyncio.Future[None] = asyncio.Future() - self._waiters.append(fut) - try: - await fut - except CancelledError: - try: - self._waiters.remove(fut) - except ValueError: - self.release() - - raise - - def acquire_nowait(self) -> None: - if self._value == 0: - raise WouldBlock - - self._value -= 1 - - def release(self) -> None: - if self._max_value is not None and self._value == self._max_value: - raise ValueError("semaphore released too many times") - - for fut in self._waiters: - if not fut.cancelled(): - fut.set_result(None) - self._waiters.remove(fut) - return - - self._value += 1 - - @property - def value(self) -> int: - return self._value - - @property - def max_value(self) -> int | None: - return self._max_value - - def statistics(self) -> SemaphoreStatistics: - return SemaphoreStatistics(len(self._waiters)) - - -class CapacityLimiter(BaseCapacityLimiter): - _total_tokens: float = 0 - - def __new__(cls, total_tokens: float) -> CapacityLimiter: - return object.__new__(cls) - - def __init__(self, total_tokens: float): - self._borrowers: set[Any] = set() - self._wait_queue: OrderedDict[Any, asyncio.Event] = OrderedDict() - self.total_tokens = total_tokens - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - @property - def total_tokens(self) -> float: - return self._total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - if not isinstance(value, int) and not math.isinf(value): - raise TypeError("total_tokens must be an int or math.inf") - - if value < 0: - raise ValueError("total_tokens must be >= 0") - - waiters_to_notify = max(value - self._total_tokens, 0) - self._total_tokens = value - - # Notify waiting tasks that they have acquired the limiter - while self._wait_queue and waiters_to_notify: - event = self._wait_queue.popitem(last=False)[1] - event.set() - waiters_to_notify -= 1 - - @property - def borrowed_tokens(self) -> int: - return len(self._borrowers) - - @property - def available_tokens(self) -> float: - return self._total_tokens - len(self._borrowers) - - def _notify_next_waiter(self) -> None: - """Notify the next task in line if this limiter has free capacity now.""" - if self._wait_queue and len(self._borrowers) < self._total_tokens: - event = self._wait_queue.popitem(last=False)[1] - event.set() - - def acquire_nowait(self) -> None: - self.acquire_on_behalf_of_nowait(current_task()) - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - if borrower in self._borrowers: - raise RuntimeError( - "this borrower is already holding one of this CapacityLimiter's tokens" - ) - - if self._wait_queue or len(self._borrowers) >= self._total_tokens: - raise WouldBlock - - self._borrowers.add(borrower) - - async def acquire(self) -> None: - return await self.acquire_on_behalf_of(current_task()) - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await AsyncIOBackend.checkpoint_if_cancelled() - try: - self.acquire_on_behalf_of_nowait(borrower) - except WouldBlock: - event = asyncio.Event() - self._wait_queue[borrower] = event - try: - await event.wait() - except BaseException: - self._wait_queue.pop(borrower, None) - if event.is_set(): - self._notify_next_waiter() - - raise - - self._borrowers.add(borrower) - else: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except BaseException: - self.release() - raise - - def release(self) -> None: - self.release_on_behalf_of(current_task()) - - def release_on_behalf_of(self, borrower: object) -> None: - try: - self._borrowers.remove(borrower) - except KeyError: - raise RuntimeError( - "this borrower isn't holding any of this CapacityLimiter's tokens" - ) from None - - self._notify_next_waiter() - - def statistics(self) -> CapacityLimiterStatistics: - return CapacityLimiterStatistics( - self.borrowed_tokens, - self.total_tokens, - tuple(self._borrowers), - len(self._wait_queue), - ) - - -_default_thread_limiter: RunVar[CapacityLimiter] = RunVar("_default_thread_limiter") - - -# -# Operating system signals -# - - -class _SignalReceiver: - def __init__(self, signals: tuple[Signals, ...]): - self._signals = signals - self._loop = get_running_loop() - self._signal_queue: deque[Signals] = deque() - self._future: asyncio.Future = asyncio.Future() - self._handled_signals: set[Signals] = set() - - def _deliver(self, signum: Signals) -> None: - self._signal_queue.append(signum) - if not self._future.done(): - self._future.set_result(None) - - def __enter__(self) -> _SignalReceiver: - for sig in set(self._signals): - self._loop.add_signal_handler(sig, self._deliver, sig) - self._handled_signals.add(sig) - - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - for sig in self._handled_signals: - self._loop.remove_signal_handler(sig) - - def __aiter__(self) -> _SignalReceiver: - return self - - async def __anext__(self) -> Signals: - await AsyncIOBackend.checkpoint() - if not self._signal_queue: - self._future = asyncio.Future() - await self._future - - return self._signal_queue.popleft() - - -# -# Testing and debugging -# - - -class AsyncIOTaskInfo(TaskInfo): - def __init__(self, task: asyncio.Task): - task_state = _task_states.get(task) - if task_state is None: - parent_id = None - else: - parent_id = task_state.parent_id - - coro = task.get_coro() - assert coro is not None, "created TaskInfo from a completed Task" - super().__init__(id(task), parent_id, task.get_name(), coro) - self._task = weakref.ref(task) - - def has_pending_cancellation(self) -> bool: - if not (task := self._task()): - # If the task isn't around anymore, it won't have a pending cancellation - return False - - if task._must_cancel: # type: ignore[attr-defined] - return True - elif ( - isinstance(task._fut_waiter, asyncio.Future) # type: ignore[attr-defined] - and task._fut_waiter.cancelled() # type: ignore[attr-defined] - ): - return True - - if task_state := _task_states.get(task): - if cancel_scope := task_state.cancel_scope: - return cancel_scope._effectively_cancelled - - return False - - -class TestRunner(abc.TestRunner): - _send_stream: MemoryObjectSendStream[tuple[Awaitable[Any], asyncio.Future[Any]]] - - def __init__( - self, - *, - debug: bool | None = None, - use_uvloop: bool = False, - loop_factory: Callable[[], AbstractEventLoop] | None = None, - ) -> None: - if use_uvloop and loop_factory is None: - if sys.platform != "win32": - import uvloop - - loop_factory = uvloop.new_event_loop - else: - import winloop - - loop_factory = winloop.new_event_loop - - self._runner = Runner(debug=debug, loop_factory=loop_factory) - self._exceptions: list[BaseException] = [] - self._runner_task: asyncio.Task | None = None - - def __enter__(self) -> TestRunner: - self._runner.__enter__() - self.get_loop().set_exception_handler(self._exception_handler) - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._runner.__exit__(exc_type, exc_val, exc_tb) - - def get_loop(self) -> AbstractEventLoop: - return self._runner.get_loop() - - def _exception_handler( - self, loop: asyncio.AbstractEventLoop, context: dict[str, Any] - ) -> None: - if isinstance(context.get("exception"), Exception): - self._exceptions.append(context["exception"]) - else: - loop.default_exception_handler(context) - - def _raise_async_exceptions(self) -> None: - # Re-raise any exceptions raised in asynchronous callbacks - if self._exceptions: - exceptions, self._exceptions = self._exceptions, [] - if len(exceptions) == 1: - raise exceptions[0] - elif exceptions: - raise BaseExceptionGroup( - "Multiple exceptions occurred in asynchronous callbacks", exceptions - ) - - async def _run_tests_and_fixtures( - self, - receive_stream: MemoryObjectReceiveStream[ - tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]] - ], - ) -> None: - from _pytest.outcomes import OutcomeException - - with receive_stream, self._send_stream: - async for coro, future in receive_stream: - try: - retval = await coro - except CancelledError as exc: - if not future.cancelled(): - future.cancel(*exc.args) - - raise - except BaseException as exc: - if not future.cancelled(): - future.set_exception(exc) - - if not isinstance(exc, (Exception, OutcomeException)): - raise - else: - if not future.cancelled(): - future.set_result(retval) - - async def _call_in_runner_task( - self, - func: Callable[P, Awaitable[T_Retval]], - *args: P.args, - **kwargs: P.kwargs, - ) -> T_Retval: - if not self._runner_task: - self._send_stream, receive_stream = create_memory_object_stream[ - tuple[Awaitable[Any], asyncio.Future] - ](1) - self._runner_task = self.get_loop().create_task( - self._run_tests_and_fixtures(receive_stream) - ) - - coro = func(*args, **kwargs) - future: asyncio.Future[T_Retval] = self.get_loop().create_future() - self._send_stream.send_nowait((coro, future)) - return await future - - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], - kwargs: dict[str, Any], - ) -> Iterable[T_Retval]: - asyncgen = fixture_func(**kwargs) - fixturevalue: T_Retval = self.get_loop().run_until_complete( - self._call_in_runner_task(asyncgen.asend, None) - ) - self._raise_async_exceptions() - - yield fixturevalue - - try: - self.get_loop().run_until_complete( - self._call_in_runner_task(asyncgen.asend, None) - ) - except StopAsyncIteration: - self._raise_async_exceptions() - else: - self.get_loop().run_until_complete(asyncgen.aclose()) - raise RuntimeError("Async generator fixture did not stop") - - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], - kwargs: dict[str, Any], - ) -> T_Retval: - retval = self.get_loop().run_until_complete( - self._call_in_runner_task(fixture_func, **kwargs) - ) - self._raise_async_exceptions() - return retval - - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - try: - self.get_loop().run_until_complete( - self._call_in_runner_task(test_func, **kwargs) - ) - except Exception as exc: - self._exceptions.append(exc) - - self._raise_async_exceptions() - - -class AsyncIOBackend(AsyncBackend): - @classmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - @wraps(func) - async def wrapper() -> T_Retval: - task = cast(asyncio.Task, current_task()) - task.set_name(get_callable_name(func)) - _task_states[task] = TaskState(None, None) - - try: - return await func(*args) - finally: - del _task_states[task] - - debug = options.get("debug", None) - loop_factory = options.get("loop_factory", None) - if loop_factory is None and options.get("use_uvloop", False): - if sys.platform != "win32": - import uvloop - - loop_factory = uvloop.new_event_loop - else: - import winloop - - loop_factory = winloop.new_event_loop - - with Runner(debug=debug, loop_factory=loop_factory) as runner: - return runner.run(wrapper()) - - @classmethod - def current_token(cls) -> object: - return get_running_loop() - - @classmethod - def current_time(cls) -> float: - return get_running_loop().time() - - @classmethod - def cancelled_exception_class(cls) -> type[BaseException]: - return CancelledError - - @classmethod - async def checkpoint(cls) -> None: - await sleep(0) - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - task = current_task() - if task is None: - return - - try: - cancel_scope = _task_states[task].cancel_scope - except KeyError: - return - - while cancel_scope: - if cancel_scope.cancel_called: - await sleep(0) - elif cancel_scope.shield: - break - else: - cancel_scope = cancel_scope._parent_scope - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - with CancelScope(shield=True): - await sleep(0) - - @classmethod - async def sleep(cls, delay: float) -> None: - await sleep(delay) - - @classmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return CancelScope(deadline=deadline, shield=shield) - - @classmethod - def current_effective_deadline(cls) -> float: - if (task := current_task()) is None: - return math.inf - - try: - cancel_scope = _task_states[task].cancel_scope - except KeyError: - return math.inf - - deadline = math.inf - while cancel_scope: - deadline = min(deadline, cancel_scope.deadline) - if cancel_scope._cancel_called: - deadline = -math.inf - break - elif cancel_scope.shield: - break - else: - cancel_scope = cancel_scope._parent_scope - - return deadline - - @classmethod - def create_task_group(cls) -> abc.TaskGroup: - return TaskGroup() - - @classmethod - def create_event(cls) -> abc.Event: - return Event() - - @classmethod - def create_lock(cls, *, fast_acquire: bool) -> abc.Lock: - return Lock(fast_acquire=fast_acquire) - - @classmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> abc.Semaphore: - return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) - - @classmethod - def create_capacity_limiter(cls, total_tokens: float) -> abc.CapacityLimiter: - return CapacityLimiter(total_tokens) - - @classmethod - async def run_sync_in_worker_thread( # type: ignore[return] - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: abc.CapacityLimiter | None = None, - ) -> T_Retval: - await cls.checkpoint() - - # If this is the first run in this event loop thread, set up the necessary - # variables - try: - idle_workers = _threadpool_idle_workers.get() - workers = _threadpool_workers.get() - except LookupError: - idle_workers = deque() - workers = set() - _threadpool_idle_workers.set(idle_workers) - _threadpool_workers.set(workers) - - async with limiter or cls.current_default_thread_limiter(): - with CancelScope(shield=not abandon_on_cancel) as scope: - future = asyncio.Future[T_Retval]() - root_task = find_root_task() - if not idle_workers: - worker = WorkerThread(root_task, workers, idle_workers) - worker.start() - workers.add(worker) - root_task.add_done_callback( - worker.stop, context=contextvars.Context() - ) - else: - worker = idle_workers.pop() - - # Prune any other workers that have been idle for MAX_IDLE_TIME - # seconds or longer - now = cls.current_time() - while idle_workers: - if ( - now - idle_workers[0].idle_since - < WorkerThread.MAX_IDLE_TIME - ): - break - - expired_worker = idle_workers.popleft() - expired_worker.root_task.remove_done_callback( - expired_worker.stop - ) - expired_worker.stop() - - context = copy_context() - context.run(set_current_async_library, None) - if abandon_on_cancel or scope._parent_scope is None: - worker_scope = scope - else: - worker_scope = scope._parent_scope - - worker.queue.put_nowait((context, func, args, future, worker_scope)) - return await future - - @classmethod - def check_cancelled(cls) -> None: - scope: CancelScope | None = threadlocals.current_cancel_scope - while scope is not None: - if scope.cancel_called: - raise CancelledError(f"Cancelled by cancel scope {id(scope):x}") - - if scope.shield: - return - - scope = scope._parent_scope - - @classmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - async def task_wrapper() -> T_Retval: - __tracebackhide__ = True - if scope is not None: - task = cast(asyncio.Task, current_task()) - _task_states[task] = TaskState(None, scope) - scope._tasks.add(task) - try: - return await func(*args) - except CancelledError as exc: - raise concurrent.futures.CancelledError(str(exc)) from None - finally: - if scope is not None: - scope._tasks.discard(task) - - loop = cast( - "AbstractEventLoop", token or threadlocals.current_token.native_token - ) - if loop.is_closed(): - raise RunFinishedError - - context = copy_context() - context.run(set_current_async_library, "asyncio") - scope = getattr(threadlocals, "current_cancel_scope", None) - f: concurrent.futures.Future[T_Retval] = context.run( - asyncio.run_coroutine_threadsafe, task_wrapper(), loop=loop - ) - return f.result() - - @classmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - @wraps(func) - def wrapper() -> None: - try: - set_current_async_library("asyncio") - f.set_result(func(*args)) - except BaseException as exc: - f.set_exception(exc) - if not isinstance(exc, Exception): - raise - - loop = cast( - "AbstractEventLoop", token or threadlocals.current_token.native_token - ) - if loop.is_closed(): - raise RunFinishedError - - f: concurrent.futures.Future[T_Retval] = Future() - loop.call_soon_threadsafe(wrapper) - return f.result() - - @classmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - await cls.checkpoint() - if isinstance(command, PathLike): - command = os.fspath(command) - - if isinstance(command, (str, bytes)): - process = await asyncio.create_subprocess_shell( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - **kwargs, - ) - else: - process = await asyncio.create_subprocess_exec( - *command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - **kwargs, - ) - - stdin_stream = StreamWriterWrapper(process.stdin) if process.stdin else None - stdout_stream = StreamReaderWrapper(process.stdout) if process.stdout else None - stderr_stream = StreamReaderWrapper(process.stderr) if process.stderr else None - return Process(process, stdin_stream, stdout_stream, stderr_stream) - - @classmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: - create_task( - _shutdown_process_pool_on_exit(workers), - name="AnyIO process pool shutdown task", - ) - find_root_task().add_done_callback( - partial(_forcibly_shutdown_process_pool_on_exit, workers) # type:ignore[arg-type] - ) - - @classmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> abc.SocketStream: - transport, protocol = cast( - tuple[asyncio.Transport, StreamProtocol], - await get_running_loop().create_connection( - StreamProtocol, host, port, local_addr=local_address - ), - ) - transport.pause_reading() - return SocketStream(transport, protocol) - - @classmethod - async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: - await cls.checkpoint() - loop = get_running_loop() - raw_socket = socket.socket(socket.AF_UNIX) - raw_socket.setblocking(False) - while True: - try: - raw_socket.connect(path) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - loop.add_writer(raw_socket, f.set_result, None) - f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) - await f - except BaseException: - raw_socket.close() - raise - else: - return UNIXSocketStream(raw_socket) - - @classmethod - def create_tcp_listener(cls, sock: socket.socket) -> SocketListener: - return TCPSocketListener(sock) - - @classmethod - def create_unix_listener(cls, sock: socket.socket) -> SocketListener: - return UNIXSocketListener(sock) - - @classmethod - async def create_udp_socket( - cls, - family: AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, - local_addr=local_address, - remote_addr=remote_address, - family=family, - reuse_port=reuse_port, - ) - if protocol.exception: - transport.close() - raise protocol.exception - - if not remote_address: - return UDPSocket(transport, protocol) - else: - return ConnectedUDPSocket(transport, protocol) - - @classmethod - async def create_unix_datagram_socket( # type: ignore[override] - cls, raw_socket: socket.socket, remote_path: str | bytes | None - ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: - await cls.checkpoint() - loop = get_running_loop() - - if remote_path: - while True: - try: - raw_socket.connect(remote_path) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - loop.add_writer(raw_socket, f.set_result, None) - f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) - await f - except BaseException: - raw_socket.close() - raise - else: - return ConnectedUNIXDatagramSocket(raw_socket) - else: - return UNIXDatagramSocket(raw_socket) - - @classmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - return await get_running_loop().getaddrinfo( - host, port, family=family, type=type, proto=proto, flags=flags - ) - - @classmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - return await get_running_loop().getnameinfo(sockaddr, flags) - - @classmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - try: - read_events = _read_events.get() - except LookupError: - read_events = {} - _read_events.set(read_events) - - fd = obj if isinstance(obj, int) else obj.fileno() - if read_events.get(fd): - raise BusyResourceError("reading from") - - loop = get_running_loop() - fut: asyncio.Future[bool] = loop.create_future() - - def cb() -> None: - try: - del read_events[fd] - except KeyError: - pass - else: - remove_reader(fd) - - try: - fut.set_result(True) - except asyncio.InvalidStateError: - pass - - try: - loop.add_reader(fd, cb) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - selector = get_selector() - selector.add_reader(fd, cb) - remove_reader = selector.remove_reader - else: - remove_reader = loop.remove_reader - - read_events[fd] = fut - try: - success = await fut - finally: - try: - del read_events[fd] - except KeyError: - pass - else: - remove_reader(fd) - - if not success: - raise ClosedResourceError - - @classmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - try: - write_events = _write_events.get() - except LookupError: - write_events = {} - _write_events.set(write_events) - - fd = obj if isinstance(obj, int) else obj.fileno() - if write_events.get(fd): - raise BusyResourceError("writing to") - - loop = get_running_loop() - fut: asyncio.Future[bool] = loop.create_future() - - def cb() -> None: - try: - del write_events[fd] - except KeyError: - pass - else: - remove_writer(fd) - - try: - fut.set_result(True) - except asyncio.InvalidStateError: - pass - - try: - loop.add_writer(fd, cb) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - selector = get_selector() - selector.add_writer(fd, cb) - remove_writer = selector.remove_writer - else: - remove_writer = loop.remove_writer - - write_events[fd] = fut - try: - success = await fut - finally: - try: - del write_events[fd] - except KeyError: - pass - else: - remove_writer(fd) - - if not success: - raise ClosedResourceError - - @classmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - fd = obj if isinstance(obj, int) else obj.fileno() - loop = get_running_loop() - - try: - write_events = _write_events.get() - except LookupError: - pass - else: - try: - fut = write_events.pop(fd) - except KeyError: - pass - else: - try: - fut.set_result(False) - except asyncio.InvalidStateError: - pass - - try: - loop.remove_writer(fd) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - get_selector().remove_writer(fd) - - try: - read_events = _read_events.get() - except LookupError: - pass - else: - try: - fut = read_events.pop(fd) - except KeyError: - pass - else: - try: - fut.set_result(False) - except asyncio.InvalidStateError: - pass - - try: - loop.remove_reader(fd) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - get_selector().remove_reader(fd) - - @classmethod - async def wrap_listener_socket(cls, sock: socket.socket) -> SocketListener: - return TCPSocketListener(sock) - - @classmethod - async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: - transport, protocol = await get_running_loop().create_connection( - StreamProtocol, sock=sock - ) - return SocketStream(transport, protocol) - - @classmethod - async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: - return UNIXSocketStream(sock) - - @classmethod - async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, sock=sock - ) - return UDPSocket(transport, protocol) - - @classmethod - async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, sock=sock - ) - return ConnectedUDPSocket(transport, protocol) - - @classmethod - async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: - return UNIXDatagramSocket(sock) - - @classmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket.socket - ) -> ConnectedUNIXDatagramSocket: - return ConnectedUNIXDatagramSocket(sock) - - @classmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - try: - return _default_thread_limiter.get() - except LookupError: - limiter = CapacityLimiter(40) - _default_thread_limiter.set(limiter) - return limiter - - @classmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - return _SignalReceiver(signals) - - @classmethod - def get_current_task(cls) -> TaskInfo: - return AsyncIOTaskInfo(current_task()) # type: ignore[arg-type] - - @classmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - return [AsyncIOTaskInfo(task) for task in all_tasks() if not task.done()] - - @classmethod - async def wait_all_tasks_blocked(cls) -> None: - await cls.checkpoint() - this_task = current_task() - while True: - for task in all_tasks(): - if task is this_task: - continue - - waiter = task._fut_waiter # type: ignore[attr-defined] - if waiter is None or waiter.done(): - await sleep(0.1) - break - else: - return - - @classmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - return TestRunner(**options) - - -backend_class = AsyncIOBackend diff --git a/venv/lib/python3.10/site-packages/anyio/_backends/_trio.py b/venv/lib/python3.10/site-packages/anyio/_backends/_trio.py deleted file mode 100644 index f460a7f5e0072a8cec103dfb8f4887d15fa666d0..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_backends/_trio.py +++ /dev/null @@ -1,1346 +0,0 @@ -from __future__ import annotations - -import array -import math -import os -import socket -import sys -import types -import weakref -from collections.abc import ( - AsyncGenerator, - AsyncIterator, - Awaitable, - Callable, - Collection, - Coroutine, - Iterable, - Sequence, -) -from contextlib import AbstractContextManager -from dataclasses import dataclass -from io import IOBase -from os import PathLike -from signal import Signals -from socket import AddressFamily, SocketKind -from types import TracebackType -from typing import ( - IO, - TYPE_CHECKING, - Any, - Generic, - NoReturn, - TypeVar, - cast, - overload, -) - -import trio.from_thread -import trio.lowlevel -from outcome import Error, Outcome, Value -from trio.lowlevel import ( - current_root_task, - current_task, - notify_closing, - wait_readable, - wait_writable, -) -from trio.socket import SocketType as TrioSocketType -from trio.to_thread import run_sync - -from .. import ( - CapacityLimiterStatistics, - EventStatistics, - LockStatistics, - RunFinishedError, - TaskInfo, - WouldBlock, - abc, -) -from .._core._eventloop import claim_worker_thread -from .._core._exceptions import ( - BrokenResourceError, - BusyResourceError, - ClosedResourceError, - EndOfStream, -) -from .._core._sockets import convert_ipv6_sockaddr -from .._core._streams import create_memory_object_stream -from .._core._synchronization import ( - CapacityLimiter as BaseCapacityLimiter, -) -from .._core._synchronization import Event as BaseEvent -from .._core._synchronization import Lock as BaseLock -from .._core._synchronization import ( - ResourceGuard, - SemaphoreStatistics, -) -from .._core._synchronization import Semaphore as BaseSemaphore -from .._core._tasks import CancelScope as BaseCancelScope -from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType -from ..abc._eventloop import AsyncBackend, StrOrBytesPath -from ..streams.memory import MemoryObjectSendStream - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - -if sys.version_info >= (3, 10): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from exceptiongroup import BaseExceptionGroup - from typing_extensions import TypeVarTuple, Unpack - -T = TypeVar("T") -T_Retval = TypeVar("T_Retval") -T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType) -PosArgsT = TypeVarTuple("PosArgsT") -P = ParamSpec("P") - - -# -# Event loop -# - -RunVar = trio.lowlevel.RunVar - - -# -# Timeouts and cancellation -# - - -class CancelScope(BaseCancelScope): - def __new__( - cls, original: trio.CancelScope | None = None, **kwargs: object - ) -> CancelScope: - return object.__new__(cls) - - def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None: - self.__original = original or trio.CancelScope(**kwargs) - - def __enter__(self) -> CancelScope: - self.__original.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - return self.__original.__exit__(exc_type, exc_val, exc_tb) - - def cancel(self, reason: str | None = None) -> None: - self.__original.cancel(reason) - - @property - def deadline(self) -> float: - return self.__original.deadline - - @deadline.setter - def deadline(self, value: float) -> None: - self.__original.deadline = value - - @property - def cancel_called(self) -> bool: - return self.__original.cancel_called - - @property - def cancelled_caught(self) -> bool: - return self.__original.cancelled_caught - - @property - def shield(self) -> bool: - return self.__original.shield - - @shield.setter - def shield(self, value: bool) -> None: - self.__original.shield = value - - -# -# Task groups -# - - -class TaskGroup(abc.TaskGroup): - def __init__(self) -> None: - self._active = False - self._nursery_manager = trio.open_nursery(strict_exception_groups=True) - self.cancel_scope = None # type: ignore[assignment] - - async def __aenter__(self) -> TaskGroup: - self._active = True - self._nursery = await self._nursery_manager.__aenter__() - self.cancel_scope = CancelScope(self._nursery.cancel_scope) - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - try: - # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type - return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value] - except BaseExceptionGroup as exc: - if not exc.split(trio.Cancelled)[1]: - raise trio.Cancelled._create() from exc - - raise - finally: - del exc_val, exc_tb - self._active = False - - def start_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> None: - if not self._active: - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - self._nursery.start_soon(func, *args, name=name) - - async def start( - self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None - ) -> Any: - if not self._active: - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - return await self._nursery.start(func, *args, name=name) - - -# -# Subprocesses -# - - -@dataclass(eq=False) -class ReceiveStreamWrapper(abc.ByteReceiveStream): - _stream: trio.abc.ReceiveStream - - async def receive(self, max_bytes: int | None = None) -> bytes: - try: - data = await self._stream.receive_some(max_bytes) - except trio.ClosedResourceError as exc: - raise ClosedResourceError from exc.__cause__ - except trio.BrokenResourceError as exc: - raise BrokenResourceError from exc.__cause__ - - if data: - return bytes(data) - else: - raise EndOfStream - - async def aclose(self) -> None: - await self._stream.aclose() - - -@dataclass(eq=False) -class SendStreamWrapper(abc.ByteSendStream): - _stream: trio.abc.SendStream - - async def send(self, item: bytes) -> None: - try: - await self._stream.send_all(item) - except trio.ClosedResourceError as exc: - raise ClosedResourceError from exc.__cause__ - except trio.BrokenResourceError as exc: - raise BrokenResourceError from exc.__cause__ - - async def aclose(self) -> None: - await self._stream.aclose() - - -@dataclass(eq=False) -class Process(abc.Process): - _process: trio.Process - _stdin: abc.ByteSendStream | None - _stdout: abc.ByteReceiveStream | None - _stderr: abc.ByteReceiveStream | None - - async def aclose(self) -> None: - with CancelScope(shield=True): - if self._stdin: - await self._stdin.aclose() - if self._stdout: - await self._stdout.aclose() - if self._stderr: - await self._stderr.aclose() - - try: - await self.wait() - except BaseException: - self.kill() - with CancelScope(shield=True): - await self.wait() - raise - - async def wait(self) -> int: - return await self._process.wait() - - def terminate(self) -> None: - self._process.terminate() - - def kill(self) -> None: - self._process.kill() - - def send_signal(self, signal: Signals) -> None: - self._process.send_signal(signal) - - @property - def pid(self) -> int: - return self._process.pid - - @property - def returncode(self) -> int | None: - return self._process.returncode - - @property - def stdin(self) -> abc.ByteSendStream | None: - return self._stdin - - @property - def stdout(self) -> abc.ByteReceiveStream | None: - return self._stdout - - @property - def stderr(self) -> abc.ByteReceiveStream | None: - return self._stderr - - -class _ProcessPoolShutdownInstrument(trio.abc.Instrument): - def after_run(self) -> None: - super().after_run() - - -current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar( - "current_default_worker_process_limiter" -) - - -async def _shutdown_process_pool(workers: set[abc.Process]) -> None: - try: - await trio.sleep(math.inf) - except trio.Cancelled: - for process in workers: - if process.returncode is None: - process.kill() - - with CancelScope(shield=True): - for process in workers: - await process.aclose() - - -# -# Sockets and networking -# - - -class _TrioSocketMixin(Generic[T_SockAddr]): - def __init__(self, trio_socket: TrioSocketType) -> None: - self._trio_socket = trio_socket - self._closed = False - - def _check_closed(self) -> None: - if self._closed: - raise ClosedResourceError - if self._trio_socket.fileno() < 0: - raise BrokenResourceError - - @property - def _raw_socket(self) -> socket.socket: - return self._trio_socket._sock # type: ignore[attr-defined] - - async def aclose(self) -> None: - if self._trio_socket.fileno() >= 0: - self._closed = True - self._trio_socket.close() - - def _convert_socket_error(self, exc: BaseException) -> NoReturn: - if isinstance(exc, trio.ClosedResourceError): - raise ClosedResourceError from exc - elif self._trio_socket.fileno() < 0 and self._closed: - raise ClosedResourceError from None - elif isinstance(exc, OSError): - raise BrokenResourceError from exc - else: - raise exc - - -class SocketStream(_TrioSocketMixin, abc.SocketStream): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self, max_bytes: int = 65536) -> bytes: - with self._receive_guard: - try: - data = await self._trio_socket.recv(max_bytes) - except BaseException as exc: - self._convert_socket_error(exc) - - if data: - return data - else: - raise EndOfStream - - async def send(self, item: bytes) -> None: - with self._send_guard: - view = memoryview(item) - while view: - try: - bytes_sent = await self._trio_socket.send(view) - except BaseException as exc: - self._convert_socket_error(exc) - - view = view[bytes_sent:] - - async def send_eof(self) -> None: - self._trio_socket.shutdown(socket.SHUT_WR) - - -class UNIXSocketStream(SocketStream, abc.UNIXSocketStream): - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - if not isinstance(msglen, int) or msglen < 0: - raise ValueError("msglen must be a non-negative integer") - if not isinstance(maxfds, int) or maxfds < 1: - raise ValueError("maxfds must be a positive integer") - - fds = array.array("i") - await trio.lowlevel.checkpoint() - with self._receive_guard: - while True: - try: - message, ancdata, flags, addr = await self._trio_socket.recvmsg( - msglen, socket.CMSG_LEN(maxfds * fds.itemsize) - ) - except BaseException as exc: - self._convert_socket_error(exc) - else: - if not message and not ancdata: - raise EndOfStream - - break - - for cmsg_level, cmsg_type, cmsg_data in ancdata: - if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: - raise RuntimeError( - f"Received unexpected ancillary data; message = {message!r}, " - f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" - ) - - fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) - - return message, list(fds) - - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - if not message: - raise ValueError("message must not be empty") - if not fds: - raise ValueError("fds must not be empty") - - filenos: list[int] = [] - for fd in fds: - if isinstance(fd, int): - filenos.append(fd) - elif isinstance(fd, IOBase): - filenos.append(fd.fileno()) - - fdarray = array.array("i", filenos) - await trio.lowlevel.checkpoint() - with self._send_guard: - while True: - try: - await self._trio_socket.sendmsg( - [message], - [ - ( - socket.SOL_SOCKET, - socket.SCM_RIGHTS, - fdarray, - ) - ], - ) - break - except BaseException as exc: - self._convert_socket_error(exc) - - -class TCPSocketListener(_TrioSocketMixin, abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - super().__init__(trio.socket.from_stdlib_socket(raw_socket)) - self._accept_guard = ResourceGuard("accepting connections from") - - async def accept(self) -> SocketStream: - with self._accept_guard: - try: - trio_socket, _addr = await self._trio_socket.accept() - except BaseException as exc: - self._convert_socket_error(exc) - - trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - return SocketStream(trio_socket) - - -class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - super().__init__(trio.socket.from_stdlib_socket(raw_socket)) - self._accept_guard = ResourceGuard("accepting connections from") - - async def accept(self) -> UNIXSocketStream: - with self._accept_guard: - try: - trio_socket, _addr = await self._trio_socket.accept() - except BaseException as exc: - self._convert_socket_error(exc) - - return UNIXSocketStream(trio_socket) - - -class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> tuple[bytes, IPSockAddrType]: - with self._receive_guard: - try: - data, addr = await self._trio_socket.recvfrom(65536) - return data, convert_ipv6_sockaddr(addr) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: UDPPacketType) -> None: - with self._send_guard: - try: - await self._trio_socket.sendto(*item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> bytes: - with self._receive_guard: - try: - return await self._trio_socket.recv(65536) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: bytes) -> None: - with self._send_guard: - try: - await self._trio_socket.send(item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> UNIXDatagramPacketType: - with self._receive_guard: - try: - data, addr = await self._trio_socket.recvfrom(65536) - return data, addr - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: UNIXDatagramPacketType) -> None: - with self._send_guard: - try: - await self._trio_socket.sendto(*item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class ConnectedUNIXDatagramSocket( - _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket -): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> bytes: - with self._receive_guard: - try: - return await self._trio_socket.recv(65536) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: bytes) -> None: - with self._send_guard: - try: - await self._trio_socket.send(item) - except BaseException as exc: - self._convert_socket_error(exc) - - -# -# Synchronization -# - - -class Event(BaseEvent): - def __new__(cls) -> Event: - return object.__new__(cls) - - def __init__(self) -> None: - self.__original = trio.Event() - - def is_set(self) -> bool: - return self.__original.is_set() - - async def wait(self) -> None: - return await self.__original.wait() - - def statistics(self) -> EventStatistics: - orig_statistics = self.__original.statistics() - return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting) - - def set(self) -> None: - self.__original.set() - - -class Lock(BaseLock): - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False) -> None: - self._fast_acquire = fast_acquire - self.__original = trio.Lock() - - @staticmethod - def _convert_runtime_error_msg(exc: RuntimeError) -> None: - if exc.args == ("attempt to re-acquire an already held Lock",): - exc.args = ("Attempted to acquire an already held Lock",) - - async def acquire(self) -> None: - if not self._fast_acquire: - try: - await self.__original.acquire() - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - return - - # This is the "fast path" where we don't let other tasks run - await trio.lowlevel.checkpoint_if_cancelled() - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - await self.__original._lot.park() - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - def acquire_nowait(self) -> None: - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - raise WouldBlock from None - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - def locked(self) -> bool: - return self.__original.locked() - - def release(self) -> None: - self.__original.release() - - def statistics(self) -> LockStatistics: - orig_statistics = self.__original.statistics() - owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None - return LockStatistics( - orig_statistics.locked, owner, orig_statistics.tasks_waiting - ) - - -class Semaphore(BaseSemaphore): - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> None: - super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) - self.__original = trio.Semaphore(initial_value, max_value=max_value) - - async def acquire(self) -> None: - if not self._fast_acquire: - await self.__original.acquire() - return - - # This is the "fast path" where we don't let other tasks run - await trio.lowlevel.checkpoint_if_cancelled() - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - await self.__original._lot.park() - - def acquire_nowait(self) -> None: - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - raise WouldBlock from None - - @property - def max_value(self) -> int | None: - return self.__original.max_value - - @property - def value(self) -> int: - return self.__original.value - - def release(self) -> None: - self.__original.release() - - def statistics(self) -> SemaphoreStatistics: - orig_statistics = self.__original.statistics() - return SemaphoreStatistics(orig_statistics.tasks_waiting) - - -class CapacityLimiter(BaseCapacityLimiter): - def __new__( - cls, - total_tokens: float | None = None, - *, - original: trio.CapacityLimiter | None = None, - ) -> CapacityLimiter: - return object.__new__(cls) - - def __init__( - self, - total_tokens: float | None = None, - *, - original: trio.CapacityLimiter | None = None, - ) -> None: - if original is not None: - self.__original = original - else: - assert total_tokens is not None - self.__original = trio.CapacityLimiter(total_tokens) - - async def __aenter__(self) -> None: - return await self.__original.__aenter__() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.__original.__aexit__(exc_type, exc_val, exc_tb) - - @property - def total_tokens(self) -> float: - return self.__original.total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - self.__original.total_tokens = value - - @property - def borrowed_tokens(self) -> int: - return self.__original.borrowed_tokens - - @property - def available_tokens(self) -> float: - return self.__original.available_tokens - - def acquire_nowait(self) -> None: - self.__original.acquire_nowait() - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - self.__original.acquire_on_behalf_of_nowait(borrower) - - async def acquire(self) -> None: - await self.__original.acquire() - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await self.__original.acquire_on_behalf_of(borrower) - - def release(self) -> None: - return self.__original.release() - - def release_on_behalf_of(self, borrower: object) -> None: - return self.__original.release_on_behalf_of(borrower) - - def statistics(self) -> CapacityLimiterStatistics: - orig = self.__original.statistics() - return CapacityLimiterStatistics( - borrowed_tokens=orig.borrowed_tokens, - total_tokens=orig.total_tokens, - borrowers=tuple(orig.borrowers), - tasks_waiting=orig.tasks_waiting, - ) - - -_capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper") - - -# -# Signal handling -# - - -class _SignalReceiver: - _iterator: AsyncIterator[int] - - def __init__(self, signals: tuple[Signals, ...]): - self._signals = signals - - def __enter__(self) -> _SignalReceiver: - self._cm = trio.open_signal_receiver(*self._signals) - self._iterator = self._cm.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool | None: - return self._cm.__exit__(exc_type, exc_val, exc_tb) - - def __aiter__(self) -> _SignalReceiver: - return self - - async def __anext__(self) -> Signals: - signum = await self._iterator.__anext__() - return Signals(signum) - - -# -# Testing and debugging -# - - -class TestRunner(abc.TestRunner): - def __init__(self, **options: Any) -> None: - from queue import Queue - - self._call_queue: Queue[Callable[[], object]] = Queue() - self._send_stream: MemoryObjectSendStream | None = None - self._options = options - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: types.TracebackType | None, - ) -> None: - if self._send_stream: - self._send_stream.close() - while self._send_stream is not None: - self._call_queue.get()() - - async def _run_tests_and_fixtures(self) -> None: - self._send_stream, receive_stream = create_memory_object_stream(1) - with receive_stream: - async for coro, outcome_holder in receive_stream: - try: - retval = await coro - except BaseException as exc: - outcome_holder.append(Error(exc)) - else: - outcome_holder.append(Value(retval)) - - def _main_task_finished(self, outcome: object) -> None: - self._send_stream = None - - def _call_in_runner_task( - self, - func: Callable[P, Awaitable[T_Retval]], - *args: P.args, - **kwargs: P.kwargs, - ) -> T_Retval: - if self._send_stream is None: - trio.lowlevel.start_guest_run( - self._run_tests_and_fixtures, - run_sync_soon_threadsafe=self._call_queue.put, - done_callback=self._main_task_finished, - **self._options, - ) - while self._send_stream is None: - self._call_queue.get()() - - outcome_holder: list[Outcome] = [] - self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder)) - while not outcome_holder: - self._call_queue.get()() - - return outcome_holder[0].unwrap() - - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], - kwargs: dict[str, Any], - ) -> Iterable[T_Retval]: - asyncgen = fixture_func(**kwargs) - fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None) - - yield fixturevalue - - try: - self._call_in_runner_task(asyncgen.asend, None) - except StopAsyncIteration: - pass - else: - self._call_in_runner_task(asyncgen.aclose) - raise RuntimeError("Async generator fixture did not stop") - - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], - kwargs: dict[str, Any], - ) -> T_Retval: - return self._call_in_runner_task(fixture_func, **kwargs) - - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - self._call_in_runner_task(test_func, **kwargs) - - -class TrioTaskInfo(TaskInfo): - def __init__(self, task: trio.lowlevel.Task): - parent_id = None - if task.parent_nursery and task.parent_nursery.parent_task: - parent_id = id(task.parent_nursery.parent_task) - - super().__init__(id(task), parent_id, task.name, task.coro) - self._task = weakref.proxy(task) - - def has_pending_cancellation(self) -> bool: - try: - return self._task._cancel_status.effectively_cancelled - except ReferenceError: - # If the task is no longer around, it surely doesn't have a cancellation - # pending - return False - - -class TrioBackend(AsyncBackend): - @classmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - return trio.run(func, *args) - - @classmethod - def current_token(cls) -> object: - return trio.lowlevel.current_trio_token() - - @classmethod - def current_time(cls) -> float: - return trio.current_time() - - @classmethod - def cancelled_exception_class(cls) -> type[BaseException]: - return trio.Cancelled - - @classmethod - async def checkpoint(cls) -> None: - await trio.lowlevel.checkpoint() - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - await trio.lowlevel.checkpoint_if_cancelled() - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - await trio.lowlevel.cancel_shielded_checkpoint() - - @classmethod - async def sleep(cls, delay: float) -> None: - await trio.sleep(delay) - - @classmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> abc.CancelScope: - return CancelScope(deadline=deadline, shield=shield) - - @classmethod - def current_effective_deadline(cls) -> float: - return trio.current_effective_deadline() - - @classmethod - def create_task_group(cls) -> abc.TaskGroup: - return TaskGroup() - - @classmethod - def create_event(cls) -> abc.Event: - return Event() - - @classmethod - def create_lock(cls, *, fast_acquire: bool) -> Lock: - return Lock(fast_acquire=fast_acquire) - - @classmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> abc.Semaphore: - return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) - - @classmethod - def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: - return CapacityLimiter(total_tokens) - - @classmethod - async def run_sync_in_worker_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: abc.CapacityLimiter | None = None, - ) -> T_Retval: - def wrapper() -> T_Retval: - with claim_worker_thread(TrioBackend, token): - return func(*args) - - token = TrioBackend.current_token() - return await run_sync( - wrapper, - abandon_on_cancel=abandon_on_cancel, - limiter=cast(trio.CapacityLimiter, limiter), - ) - - @classmethod - def check_cancelled(cls) -> None: - trio.from_thread.check_cancelled() - - @classmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - trio_token = cast("trio.lowlevel.TrioToken | None", token) - try: - return trio.from_thread.run(func, *args, trio_token=trio_token) - except trio.RunFinishedError: - raise RunFinishedError from None - - @classmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - trio_token = cast("trio.lowlevel.TrioToken | None", token) - try: - return trio.from_thread.run_sync(func, *args, trio_token=trio_token) - except trio.RunFinishedError: - raise RunFinishedError from None - - @classmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - def convert_item(item: StrOrBytesPath) -> str: - str_or_bytes = os.fspath(item) - if isinstance(str_or_bytes, str): - return str_or_bytes - else: - return os.fsdecode(str_or_bytes) - - if isinstance(command, (str, bytes, PathLike)): - process = await trio.lowlevel.open_process( - convert_item(command), - stdin=stdin, - stdout=stdout, - stderr=stderr, - shell=True, - **kwargs, - ) - else: - process = await trio.lowlevel.open_process( - [convert_item(item) for item in command], - stdin=stdin, - stdout=stdout, - stderr=stderr, - shell=False, - **kwargs, - ) - - stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None - stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None - stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None - return Process(process, stdin_stream, stdout_stream, stderr_stream) - - @classmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: - trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers) - - @classmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> SocketStream: - family = socket.AF_INET6 if ":" in host else socket.AF_INET - trio_socket = trio.socket.socket(family) - trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - if local_address: - await trio_socket.bind(local_address) - - try: - await trio_socket.connect((host, port)) - except BaseException: - trio_socket.close() - raise - - return SocketStream(trio_socket) - - @classmethod - async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: - trio_socket = trio.socket.socket(socket.AF_UNIX) - try: - await trio_socket.connect(path) - except BaseException: - trio_socket.close() - raise - - return UNIXSocketStream(trio_socket) - - @classmethod - def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener: - return TCPSocketListener(sock) - - @classmethod - def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener: - return UNIXSocketListener(sock) - - @classmethod - async def create_udp_socket( - cls, - family: socket.AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM) - - if reuse_port: - trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - - if local_address: - await trio_socket.bind(local_address) - - if remote_address: - await trio_socket.connect(remote_address) - return ConnectedUDPSocket(trio_socket) - else: - return UDPSocket(trio_socket) - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: None - ) -> abc.UNIXDatagramSocket: ... - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: str | bytes - ) -> abc.ConnectedUNIXDatagramSocket: ... - - @classmethod - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: str | bytes | None - ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: - trio_socket = trio.socket.from_stdlib_socket(raw_socket) - - if remote_path: - await trio_socket.connect(remote_path) - return ConnectedUNIXDatagramSocket(trio_socket) - else: - return UNIXDatagramSocket(trio_socket) - - @classmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - return await trio.socket.getaddrinfo(host, port, family, type, proto, flags) - - @classmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - return await trio.socket.getnameinfo(sockaddr, flags) - - @classmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - try: - await wait_readable(obj) - except trio.ClosedResourceError as exc: - raise ClosedResourceError().with_traceback(exc.__traceback__) from None - except trio.BusyResourceError: - raise BusyResourceError("reading from") from None - - @classmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - try: - await wait_writable(obj) - except trio.ClosedResourceError as exc: - raise ClosedResourceError().with_traceback(exc.__traceback__) from None - except trio.BusyResourceError: - raise BusyResourceError("writing to") from None - - @classmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - notify_closing(obj) - - @classmethod - async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener: - return TCPSocketListener(sock) - - @classmethod - async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: - trio_sock = trio.socket.from_stdlib_socket(sock) - return SocketStream(trio_sock) - - @classmethod - async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UNIXSocketStream(trio_sock) - - @classmethod - async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UDPSocket(trio_sock) - - @classmethod - async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return ConnectedUDPSocket(trio_sock) - - @classmethod - async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UNIXDatagramSocket(trio_sock) - - @classmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket.socket - ) -> ConnectedUNIXDatagramSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return ConnectedUNIXDatagramSocket(trio_sock) - - @classmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - try: - return _capacity_limiter_wrapper.get() - except LookupError: - limiter = CapacityLimiter( - original=trio.to_thread.current_default_thread_limiter() - ) - _capacity_limiter_wrapper.set(limiter) - return limiter - - @classmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - return _SignalReceiver(signals) - - @classmethod - def get_current_task(cls) -> TaskInfo: - task = current_task() - return TrioTaskInfo(task) - - @classmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - root_task = current_root_task() - assert root_task - task_infos = [TrioTaskInfo(root_task)] - nurseries = root_task.child_nurseries - while nurseries: - new_nurseries: list[trio.Nursery] = [] - for nursery in nurseries: - for task in nursery.child_tasks: - task_infos.append(TrioTaskInfo(task)) - new_nurseries.extend(task.child_nurseries) - - nurseries = new_nurseries - - return task_infos - - @classmethod - async def wait_all_tasks_blocked(cls) -> None: - from trio.testing import wait_all_tasks_blocked - - await wait_all_tasks_blocked() - - @classmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - return TestRunner(**options) - - -backend_class = TrioBackend diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__init__.py b/venv/lib/python3.10/site-packages/anyio/_core/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index dc7d3a0fc48147d38b79847488a01aef24915bfb..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_asyncio_selector_thread.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_asyncio_selector_thread.cpython-310.pyc deleted file mode 100644 index aa70f3645a125d8382366def46b0f05e31594645..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_asyncio_selector_thread.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_contextmanagers.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_contextmanagers.cpython-310.pyc deleted file mode 100644 index 06b0b1fca2c760bd62df97c85ceb024244ffa324..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_contextmanagers.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_eventloop.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_eventloop.cpython-310.pyc deleted file mode 100644 index 7dbeea73d0c606b427fb0777a3dbaf7e735185c6..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_eventloop.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_exceptions.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_exceptions.cpython-310.pyc deleted file mode 100644 index 79fd83419a14a266bb4367e9afc6c4436f6cae4d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_exceptions.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_fileio.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_fileio.cpython-310.pyc deleted file mode 100644 index 3ed2fb9268c309b8a59dedfa795c3c300ecd15ab..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_fileio.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_resources.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_resources.cpython-310.pyc deleted file mode 100644 index ddcb5dfb9d3f6952697cef0fd7c92d547ac0db73..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_resources.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_signals.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_signals.cpython-310.pyc deleted file mode 100644 index 25500876a301b70d2001e582aedddf20f8481150..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_signals.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_sockets.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_sockets.cpython-310.pyc deleted file mode 100644 index f53366fdc841b40bd53ae0efe2d931e3dc6af6b1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_sockets.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_streams.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_streams.cpython-310.pyc deleted file mode 100644 index 032d2571875c5017c8ad4d3734f51424a9920ff8..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_streams.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-310.pyc deleted file mode 100644 index 32b2b29662fcc77f6d00f484defdf33427a575e4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_synchronization.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_synchronization.cpython-310.pyc deleted file mode 100644 index 3f5646732fe0781e8511a27ac8d6201f93312f57..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_synchronization.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tasks.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tasks.cpython-310.pyc deleted file mode 100644 index 7d8a151dfdf0c83cef23c0615d2b8ed613b639c9..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tasks.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tempfile.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tempfile.cpython-310.pyc deleted file mode 100644 index ce94440dc72ddb23df359da7619ce6631dae5b23..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tempfile.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_testing.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_testing.cpython-310.pyc deleted file mode 100644 index 8aa8e2317cb53c0043e5930d3a5993d38e198350..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_testing.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_typedattr.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_typedattr.cpython-310.pyc deleted file mode 100644 index 8723fa123bd1308d6b01e634431b8dd6d5fb642a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_typedattr.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_asyncio_selector_thread.py b/venv/lib/python3.10/site-packages/anyio/_core/_asyncio_selector_thread.py deleted file mode 100644 index 9f35bae568e33e6a9e1219761c83cc8350fa0532..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_asyncio_selector_thread.py +++ /dev/null @@ -1,167 +0,0 @@ -from __future__ import annotations - -import asyncio -import socket -import threading -from collections.abc import Callable -from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector -from typing import TYPE_CHECKING, Any - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - -_selector_lock = threading.Lock() -_selector: Selector | None = None - - -class Selector: - def __init__(self) -> None: - self._thread = threading.Thread(target=self.run, name="AnyIO socket selector") - self._selector = DefaultSelector() - self._send, self._receive = socket.socketpair() - self._send.setblocking(False) - self._receive.setblocking(False) - # This somewhat reduces the amount of memory wasted queueing up data - # for wakeups. With these settings, maximum number of 1-byte sends - # before getting BlockingIOError: - # Linux 4.8: 6 - # macOS (darwin 15.5): 1 - # Windows 10: 525347 - # Windows you're weird. (And on Windows setting SNDBUF to 0 makes send - # blocking, even on non-blocking sockets, so don't do that.) - self._receive.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1) - self._send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1) - # On Windows this is a TCP socket so this might matter. On other - # platforms this fails b/c AF_UNIX sockets aren't actually TCP. - try: - self._send.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - except OSError: - pass - - self._selector.register(self._receive, EVENT_READ) - self._closed = False - - def start(self) -> None: - self._thread.start() - threading._register_atexit(self._stop) # type: ignore[attr-defined] - - def _stop(self) -> None: - global _selector - self._closed = True - self._notify_self() - self._send.close() - self._thread.join() - self._selector.unregister(self._receive) - self._receive.close() - self._selector.close() - _selector = None - assert not self._selector.get_map(), ( - "selector still has registered file descriptors after shutdown" - ) - - def _notify_self(self) -> None: - try: - self._send.send(b"\x00") - except BlockingIOError: - pass - - def add_reader(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: - loop = asyncio.get_running_loop() - try: - key = self._selector.get_key(fd) - except KeyError: - self._selector.register(fd, EVENT_READ, {EVENT_READ: (loop, callback)}) - else: - if EVENT_READ in key.data: - raise ValueError( - "this file descriptor is already registered for reading" - ) - - key.data[EVENT_READ] = loop, callback - self._selector.modify(fd, key.events | EVENT_READ, key.data) - - self._notify_self() - - def add_writer(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: - loop = asyncio.get_running_loop() - try: - key = self._selector.get_key(fd) - except KeyError: - self._selector.register(fd, EVENT_WRITE, {EVENT_WRITE: (loop, callback)}) - else: - if EVENT_WRITE in key.data: - raise ValueError( - "this file descriptor is already registered for writing" - ) - - key.data[EVENT_WRITE] = loop, callback - self._selector.modify(fd, key.events | EVENT_WRITE, key.data) - - self._notify_self() - - def remove_reader(self, fd: FileDescriptorLike) -> bool: - try: - key = self._selector.get_key(fd) - except KeyError: - return False - - if new_events := key.events ^ EVENT_READ: - del key.data[EVENT_READ] - self._selector.modify(fd, new_events, key.data) - else: - self._selector.unregister(fd) - - return True - - def remove_writer(self, fd: FileDescriptorLike) -> bool: - try: - key = self._selector.get_key(fd) - except KeyError: - return False - - if new_events := key.events ^ EVENT_WRITE: - del key.data[EVENT_WRITE] - self._selector.modify(fd, new_events, key.data) - else: - self._selector.unregister(fd) - - return True - - def run(self) -> None: - while not self._closed: - for key, events in self._selector.select(): - if key.fileobj is self._receive: - try: - while self._receive.recv(4096): - pass - except BlockingIOError: - pass - - continue - - if events & EVENT_READ: - loop, callback = key.data[EVENT_READ] - self.remove_reader(key.fd) - try: - loop.call_soon_threadsafe(callback) - except RuntimeError: - pass # the loop was already closed - - if events & EVENT_WRITE: - loop, callback = key.data[EVENT_WRITE] - self.remove_writer(key.fd) - try: - loop.call_soon_threadsafe(callback) - except RuntimeError: - pass # the loop was already closed - - -def get_selector() -> Selector: - global _selector - - with _selector_lock: - if _selector is None: - _selector = Selector() - _selector.start() - - return _selector diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_contextmanagers.py b/venv/lib/python3.10/site-packages/anyio/_core/_contextmanagers.py deleted file mode 100644 index 302f32b0c78a7071605b195c55054cfdb0b55f37..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_contextmanagers.py +++ /dev/null @@ -1,200 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from contextlib import AbstractAsyncContextManager, AbstractContextManager -from inspect import isasyncgen, iscoroutine, isgenerator -from types import TracebackType -from typing import Protocol, TypeVar, cast, final - -_T_co = TypeVar("_T_co", covariant=True) -_ExitT_co = TypeVar("_ExitT_co", covariant=True, bound="bool | None") - - -class _SupportsCtxMgr(Protocol[_T_co, _ExitT_co]): - def __contextmanager__(self) -> AbstractContextManager[_T_co, _ExitT_co]: ... - - -class _SupportsAsyncCtxMgr(Protocol[_T_co, _ExitT_co]): - def __asynccontextmanager__( - self, - ) -> AbstractAsyncContextManager[_T_co, _ExitT_co]: ... - - -class ContextManagerMixin: - """ - Mixin class providing context manager functionality via a generator-based - implementation. - - This class allows you to implement a context manager via :meth:`__contextmanager__` - which should return a generator. The mechanics are meant to mirror those of - :func:`@contextmanager `. - - .. note:: Classes using this mix-in are not reentrant as context managers, meaning - that once you enter it, you can't re-enter before first exiting it. - - .. seealso:: :doc:`contextmanagers` - """ - - __cm: AbstractContextManager[object, bool | None] | None = None - - @final - def __enter__(self: _SupportsCtxMgr[_T_co, bool | None]) -> _T_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, ContextManagerMixin) - if self.__cm is not None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has already been entered" - ) - - cm = self.__contextmanager__() - if not isinstance(cm, AbstractContextManager): - if isgenerator(cm): - raise TypeError( - "__contextmanager__() returned a generator object instead of " - "a context manager. Did you forget to add the @contextmanager " - "decorator?" - ) - - raise TypeError( - f"__contextmanager__() did not return a context manager object, " - f"but {cm.__class__!r}" - ) - - if cm is self: - raise TypeError( - f"{self.__class__.__qualname__}.__contextmanager__() returned " - f"self. Did you forget to add the @contextmanager decorator and a " - f"'yield' statement?" - ) - - value = cm.__enter__() - self.__cm = cm - return value - - @final - def __exit__( - self: _SupportsCtxMgr[object, _ExitT_co], - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> _ExitT_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, ContextManagerMixin) - if self.__cm is None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has not been entered yet" - ) - - # Prevent circular references - cm = self.__cm - del self.__cm - - return cast(_ExitT_co, cm.__exit__(exc_type, exc_val, exc_tb)) - - @abstractmethod - def __contextmanager__(self) -> AbstractContextManager[object, bool | None]: - """ - Implement your context manager logic here. - - This method **must** be decorated with - :func:`@contextmanager `. - - .. note:: Remember that the ``yield`` will raise any exception raised in the - enclosed context block, so use a ``finally:`` block to clean up resources! - - :return: a context manager object - """ - - -class AsyncContextManagerMixin: - """ - Mixin class providing async context manager functionality via a generator-based - implementation. - - This class allows you to implement a context manager via - :meth:`__asynccontextmanager__`. The mechanics are meant to mirror those of - :func:`@asynccontextmanager `. - - .. note:: Classes using this mix-in are not reentrant as context managers, meaning - that once you enter it, you can't re-enter before first exiting it. - - .. seealso:: :doc:`contextmanagers` - """ - - __cm: AbstractAsyncContextManager[object, bool | None] | None = None - - @final - async def __aenter__(self: _SupportsAsyncCtxMgr[_T_co, bool | None]) -> _T_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, AsyncContextManagerMixin) - if self.__cm is not None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has already been entered" - ) - - cm = self.__asynccontextmanager__() - if not isinstance(cm, AbstractAsyncContextManager): - if isasyncgen(cm): - raise TypeError( - "__asynccontextmanager__() returned an async generator instead of " - "an async context manager. Did you forget to add the " - "@asynccontextmanager decorator?" - ) - elif iscoroutine(cm): - cm.close() - raise TypeError( - "__asynccontextmanager__() returned a coroutine object instead of " - "an async context manager. Did you forget to add the " - "@asynccontextmanager decorator and a 'yield' statement?" - ) - - raise TypeError( - f"__asynccontextmanager__() did not return an async context manager, " - f"but {cm.__class__!r}" - ) - - if cm is self: - raise TypeError( - f"{self.__class__.__qualname__}.__asynccontextmanager__() returned " - f"self. Did you forget to add the @asynccontextmanager decorator and a " - f"'yield' statement?" - ) - - value = await cm.__aenter__() - self.__cm = cm - return value - - @final - async def __aexit__( - self: _SupportsAsyncCtxMgr[object, _ExitT_co], - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> _ExitT_co: - assert isinstance(self, AsyncContextManagerMixin) - if self.__cm is None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has not been entered yet" - ) - - # Prevent circular references - cm = self.__cm - del self.__cm - - return cast(_ExitT_co, await cm.__aexit__(exc_type, exc_val, exc_tb)) - - @abstractmethod - def __asynccontextmanager__( - self, - ) -> AbstractAsyncContextManager[object, bool | None]: - """ - Implement your async context manager logic here. - - This method **must** be decorated with - :func:`@asynccontextmanager `. - - .. note:: Remember that the ``yield`` will raise any exception raised in the - enclosed context block, so use a ``finally:`` block to clean up resources! - - :return: an async context manager object - """ diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_eventloop.py b/venv/lib/python3.10/site-packages/anyio/_core/_eventloop.py deleted file mode 100644 index 59a69ccdf02c2989fb522bcc9af5a23f64e1f3e7..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_eventloop.py +++ /dev/null @@ -1,234 +0,0 @@ -from __future__ import annotations - -import math -import sys -import threading -from collections.abc import Awaitable, Callable, Generator -from contextlib import contextmanager -from contextvars import Token -from importlib import import_module -from typing import TYPE_CHECKING, Any, TypeVar - -from ._exceptions import NoEventLoopError - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -sniffio: Any -try: - import sniffio -except ModuleNotFoundError: - sniffio = None - -if TYPE_CHECKING: - from ..abc import AsyncBackend - -# This must be updated when new backends are introduced -BACKENDS = "asyncio", "trio" - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -threadlocals = threading.local() -loaded_backends: dict[str, type[AsyncBackend]] = {} - - -def run( - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - backend: str = "asyncio", - backend_options: dict[str, Any] | None = None, -) -> T_Retval: - """ - Run the given coroutine function in an asynchronous event loop. - - The current thread must not be already running an event loop. - - :param func: a coroutine function - :param args: positional arguments to ``func`` - :param backend: name of the asynchronous event loop implementation – currently - either ``asyncio`` or ``trio`` - :param backend_options: keyword arguments to call the backend ``run()`` - implementation with (documented :ref:`here `) - :return: the return value of the coroutine function - :raises RuntimeError: if an asynchronous event loop is already running in this - thread - :raises LookupError: if the named backend is not found - - """ - if asynclib_name := current_async_library(): - raise RuntimeError(f"Already running {asynclib_name} in this thread") - - try: - async_backend = get_async_backend(backend) - except ImportError as exc: - raise LookupError(f"No such backend: {backend}") from exc - - token = None - if asynclib_name is None: - # Since we're in control of the event loop, we can cache the name of the async - # library - token = set_current_async_library(backend) - - try: - backend_options = backend_options or {} - return async_backend.run(func, args, {}, backend_options) - finally: - reset_current_async_library(token) - - -async def sleep(delay: float) -> None: - """ - Pause the current task for the specified duration. - - :param delay: the duration, in seconds - - """ - return await get_async_backend().sleep(delay) - - -async def sleep_forever() -> None: - """ - Pause the current task until it's cancelled. - - This is a shortcut for ``sleep(math.inf)``. - - .. versionadded:: 3.1 - - """ - await sleep(math.inf) - - -async def sleep_until(deadline: float) -> None: - """ - Pause the current task until the given time. - - :param deadline: the absolute time to wake up at (according to the internal - monotonic clock of the event loop) - - .. versionadded:: 3.1 - - """ - now = current_time() - await sleep(max(deadline - now, 0)) - - -def current_time() -> float: - """ - Return the current value of the event loop's internal clock. - - :return: the clock value (seconds) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_time() - - -def get_all_backends() -> tuple[str, ...]: - """Return a tuple of the names of all built-in backends.""" - return BACKENDS - - -def get_available_backends() -> tuple[str, ...]: - """ - Test for the availability of built-in backends. - - :return a tuple of the built-in backend names that were successfully imported - - .. versionadded:: 4.12 - - """ - available_backends: list[str] = [] - for backend_name in get_all_backends(): - try: - get_async_backend(backend_name) - except ImportError: - continue - - available_backends.append(backend_name) - - return tuple(available_backends) - - -def get_cancelled_exc_class() -> type[BaseException]: - """ - Return the current async library's cancellation exception class. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().cancelled_exception_class() - - -# -# Private API -# - - -@contextmanager -def claim_worker_thread( - backend_class: type[AsyncBackend], token: object -) -> Generator[Any, None, None]: - from ..lowlevel import EventLoopToken - - threadlocals.current_token = EventLoopToken(backend_class, token) - try: - yield - finally: - del threadlocals.current_token - - -def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]: - if asynclib_name is None: - asynclib_name = current_async_library() - if not asynclib_name: - raise NoEventLoopError( - f"Not currently running on any asynchronous event loop. " - f"Available async backends: {', '.join(get_all_backends())}" - ) - - # We use our own dict instead of sys.modules to get the already imported back-end - # class because the appropriate modules in sys.modules could potentially be only - # partially initialized - try: - return loaded_backends[asynclib_name] - except KeyError: - module = import_module(f"anyio._backends._{asynclib_name}") - loaded_backends[asynclib_name] = module.backend_class - return module.backend_class - - -def current_async_library() -> str | None: - if sniffio is None: - # If sniffio is not installed, we assume we're either running asyncio or nothing - import asyncio - - try: - asyncio.get_running_loop() - return "asyncio" - except RuntimeError: - pass - else: - try: - return sniffio.current_async_library() - except sniffio.AsyncLibraryNotFoundError: - pass - - return None - - -def set_current_async_library(asynclib_name: str | None) -> Token | None: - # no-op if sniffio is not installed - if sniffio is None: - return None - - return sniffio.current_async_library_cvar.set(asynclib_name) - - -def reset_current_async_library(token: Token | None) -> None: - if token is not None: - sniffio.current_async_library_cvar.reset(token) diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_exceptions.py b/venv/lib/python3.10/site-packages/anyio/_core/_exceptions.py deleted file mode 100644 index 3776bedcd339913d609e41e2e396f3f2fd16ae9d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_exceptions.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -import sys -from collections.abc import Generator -from textwrap import dedent -from typing import Any - -if sys.version_info < (3, 11): - from exceptiongroup import BaseExceptionGroup - - -class BrokenResourceError(Exception): - """ - Raised when trying to use a resource that has been rendered unusable due to external - causes (e.g. a send stream whose peer has disconnected). - """ - - -class BrokenWorkerProcess(Exception): - """ - Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or - otherwise misbehaves. - """ - - -class BrokenWorkerInterpreter(Exception): - """ - Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is - raised in the subinterpreter. - """ - - def __init__(self, excinfo: Any): - # This was adapted from concurrent.futures.interpreter.ExecutionFailed - msg = excinfo.formatted - if not msg: - if excinfo.type and excinfo.msg: - msg = f"{excinfo.type.__name__}: {excinfo.msg}" - else: - msg = excinfo.type.__name__ or excinfo.msg - - super().__init__(msg) - self.excinfo = excinfo - - def __str__(self) -> str: - try: - formatted = self.excinfo.errdisplay - except Exception: - return super().__str__() - else: - return dedent( - f""" - {super().__str__()} - - Uncaught in the interpreter: - - {formatted} - """.strip() - ) - - -class BusyResourceError(Exception): - """ - Raised when two tasks are trying to read from or write to the same resource - concurrently. - """ - - def __init__(self, action: str): - super().__init__(f"Another task is already {action} this resource") - - -class ClosedResourceError(Exception): - """Raised when trying to use a resource that has been closed.""" - - -class ConnectionFailed(OSError): - """ - Raised when a connection attempt fails. - - .. note:: This class inherits from :exc:`OSError` for backwards compatibility. - """ - - -def iterate_exceptions( - exception: BaseException, -) -> Generator[BaseException, None, None]: - if isinstance(exception, BaseExceptionGroup): - for exc in exception.exceptions: - yield from iterate_exceptions(exc) - else: - yield exception - - -class DelimiterNotFound(Exception): - """ - Raised during - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the - maximum number of bytes has been read without the delimiter being found. - """ - - def __init__(self, max_bytes: int) -> None: - super().__init__( - f"The delimiter was not found among the first {max_bytes} bytes" - ) - - -class EndOfStream(Exception): - """ - Raised when trying to read from a stream that has been closed from the other end. - """ - - -class IncompleteRead(Exception): - """ - Raised during - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the - connection is closed before the requested amount of bytes has been read. - """ - - def __init__(self) -> None: - super().__init__( - "The stream was closed before the read operation could be completed" - ) - - -class TypedAttributeLookupError(LookupError): - """ - Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute - is not found and no default value has been given. - """ - - -class WouldBlock(Exception): - """Raised by ``X_nowait`` functions if ``X()`` would block.""" - - -class NoEventLoopError(RuntimeError): - """ - Raised by several functions that require an event loop to be running in the current - thread when there is no running event loop. - - This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` - if not calling from an AnyIO worker thread, and no ``token`` was passed. - """ - - -class RunFinishedError(RuntimeError): - """ - Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event - loop associated with the explicitly passed token has already finished. - """ - - def __init__(self) -> None: - super().__init__( - "The event loop associated with the given token has already finished" - ) diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_fileio.py b/venv/lib/python3.10/site-packages/anyio/_core/_fileio.py deleted file mode 100644 index 061f0d7e100b04a338249ae592ead886fa54335e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_fileio.py +++ /dev/null @@ -1,797 +0,0 @@ -from __future__ import annotations - -import os -import pathlib -import sys -from collections.abc import ( - AsyncIterator, - Callable, - Iterable, - Iterator, - Sequence, -) -from dataclasses import dataclass -from functools import partial -from os import PathLike -from typing import ( - IO, - TYPE_CHECKING, - Any, - AnyStr, - ClassVar, - Final, - Generic, - overload, -) - -from .. import to_thread -from ..abc import AsyncResource - -if TYPE_CHECKING: - from types import ModuleType - - from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer -else: - ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object - - -class AsyncFile(AsyncResource, Generic[AnyStr]): - """ - An asynchronous file object. - - This class wraps a standard file object and provides async friendly versions of the - following blocking methods (where available on the original file object): - - * read - * read1 - * readline - * readlines - * readinto - * readinto1 - * write - * writelines - * truncate - * seek - * tell - * flush - - All other methods are directly passed through. - - This class supports the asynchronous context manager protocol which closes the - underlying file at the end of the context block. - - This class also supports asynchronous iteration:: - - async with await open_file(...) as f: - async for line in f: - print(line) - """ - - def __init__(self, fp: IO[AnyStr]) -> None: - self._fp: Any = fp - - def __getattr__(self, name: str) -> object: - return getattr(self._fp, name) - - @property - def wrapped(self) -> IO[AnyStr]: - """The wrapped file object.""" - return self._fp - - async def __aiter__(self) -> AsyncIterator[AnyStr]: - while True: - line = await self.readline() - if line: - yield line - else: - break - - async def aclose(self) -> None: - return await to_thread.run_sync(self._fp.close) - - async def read(self, size: int = -1) -> AnyStr: - return await to_thread.run_sync(self._fp.read, size) - - async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes: - return await to_thread.run_sync(self._fp.read1, size) - - async def readline(self) -> AnyStr: - return await to_thread.run_sync(self._fp.readline) - - async def readlines(self) -> list[AnyStr]: - return await to_thread.run_sync(self._fp.readlines) - - async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int: - return await to_thread.run_sync(self._fp.readinto, b) - - async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int: - return await to_thread.run_sync(self._fp.readinto1, b) - - @overload - async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ... - - @overload - async def write(self: AsyncFile[str], b: str) -> int: ... - - async def write(self, b: ReadableBuffer | str) -> int: - return await to_thread.run_sync(self._fp.write, b) - - @overload - async def writelines( - self: AsyncFile[bytes], lines: Iterable[ReadableBuffer] - ) -> None: ... - - @overload - async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ... - - async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None: - return await to_thread.run_sync(self._fp.writelines, lines) - - async def truncate(self, size: int | None = None) -> int: - return await to_thread.run_sync(self._fp.truncate, size) - - async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: - return await to_thread.run_sync(self._fp.seek, offset, whence) - - async def tell(self) -> int: - return await to_thread.run_sync(self._fp.tell) - - async def flush(self) -> None: - return await to_thread.run_sync(self._fp.flush) - - -@overload -async def open_file( - file: str | PathLike[str] | int, - mode: OpenBinaryMode, - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - closefd: bool = ..., - opener: Callable[[str, int], int] | None = ..., -) -> AsyncFile[bytes]: ... - - -@overload -async def open_file( - file: str | PathLike[str] | int, - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - closefd: bool = ..., - opener: Callable[[str, int], int] | None = ..., -) -> AsyncFile[str]: ... - - -async def open_file( - file: str | PathLike[str] | int, - mode: str = "r", - buffering: int = -1, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - closefd: bool = True, - opener: Callable[[str, int], int] | None = None, -) -> AsyncFile[Any]: - """ - Open a file asynchronously. - - The arguments are exactly the same as for the builtin :func:`open`. - - :return: an asynchronous file object - - """ - fp = await to_thread.run_sync( - open, file, mode, buffering, encoding, errors, newline, closefd, opener - ) - return AsyncFile(fp) - - -def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]: - """ - Wrap an existing file as an asynchronous file. - - :param file: an existing file-like object - :return: an asynchronous file object - - """ - return AsyncFile(file) - - -@dataclass(eq=False) -class _PathIterator(AsyncIterator["Path"]): - iterator: Iterator[PathLike[str]] - - async def __anext__(self) -> Path: - nextval = await to_thread.run_sync( - next, self.iterator, None, abandon_on_cancel=True - ) - if nextval is None: - raise StopAsyncIteration from None - - return Path(nextval) - - -class Path: - """ - An asynchronous version of :class:`pathlib.Path`. - - This class cannot be substituted for :class:`pathlib.Path` or - :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike` - interface. - - It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for - the deprecated :meth:`~pathlib.Path.link_to` method. - - Some methods may be unavailable or have limited functionality, based on the Python - version: - - * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later) - * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later) - * :attr:`~pathlib.Path.info` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later) - * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only - available on Python 3.13 or later) - * :meth:`~pathlib.Path.move` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later) - * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available - on Python 3.12 or later) - * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later) - - Any methods that do disk I/O need to be awaited on. These methods are: - - * :meth:`~pathlib.Path.absolute` - * :meth:`~pathlib.Path.chmod` - * :meth:`~pathlib.Path.cwd` - * :meth:`~pathlib.Path.exists` - * :meth:`~pathlib.Path.expanduser` - * :meth:`~pathlib.Path.group` - * :meth:`~pathlib.Path.hardlink_to` - * :meth:`~pathlib.Path.home` - * :meth:`~pathlib.Path.is_block_device` - * :meth:`~pathlib.Path.is_char_device` - * :meth:`~pathlib.Path.is_dir` - * :meth:`~pathlib.Path.is_fifo` - * :meth:`~pathlib.Path.is_file` - * :meth:`~pathlib.Path.is_junction` - * :meth:`~pathlib.Path.is_mount` - * :meth:`~pathlib.Path.is_socket` - * :meth:`~pathlib.Path.is_symlink` - * :meth:`~pathlib.Path.lchmod` - * :meth:`~pathlib.Path.lstat` - * :meth:`~pathlib.Path.mkdir` - * :meth:`~pathlib.Path.open` - * :meth:`~pathlib.Path.owner` - * :meth:`~pathlib.Path.read_bytes` - * :meth:`~pathlib.Path.read_text` - * :meth:`~pathlib.Path.readlink` - * :meth:`~pathlib.Path.rename` - * :meth:`~pathlib.Path.replace` - * :meth:`~pathlib.Path.resolve` - * :meth:`~pathlib.Path.rmdir` - * :meth:`~pathlib.Path.samefile` - * :meth:`~pathlib.Path.stat` - * :meth:`~pathlib.Path.symlink_to` - * :meth:`~pathlib.Path.touch` - * :meth:`~pathlib.Path.unlink` - * :meth:`~pathlib.Path.walk` - * :meth:`~pathlib.Path.write_bytes` - * :meth:`~pathlib.Path.write_text` - - Additionally, the following methods return an async iterator yielding - :class:`~.Path` objects: - - * :meth:`~pathlib.Path.glob` - * :meth:`~pathlib.Path.iterdir` - * :meth:`~pathlib.Path.rglob` - """ - - __slots__ = "_path", "__weakref__" - - __weakref__: Any - - def __init__(self, *args: str | PathLike[str]) -> None: - self._path: Final[pathlib.Path] = pathlib.Path(*args) - - def __fspath__(self) -> str: - return self._path.__fspath__() - - def __str__(self) -> str: - return self._path.__str__() - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.as_posix()!r})" - - def __bytes__(self) -> bytes: - return self._path.__bytes__() - - def __hash__(self) -> int: - return self._path.__hash__() - - def __eq__(self, other: object) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__eq__(target) - - def __lt__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__lt__(target) - - def __le__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__le__(target) - - def __gt__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__gt__(target) - - def __ge__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__ge__(target) - - def __truediv__(self, other: str | PathLike[str]) -> Path: - return Path(self._path / other) - - def __rtruediv__(self, other: str | PathLike[str]) -> Path: - return Path(other) / self - - @property - def parts(self) -> tuple[str, ...]: - return self._path.parts - - @property - def drive(self) -> str: - return self._path.drive - - @property - def root(self) -> str: - return self._path.root - - @property - def anchor(self) -> str: - return self._path.anchor - - @property - def parents(self) -> Sequence[Path]: - return tuple(Path(p) for p in self._path.parents) - - @property - def parent(self) -> Path: - return Path(self._path.parent) - - @property - def name(self) -> str: - return self._path.name - - @property - def suffix(self) -> str: - return self._path.suffix - - @property - def suffixes(self) -> list[str]: - return self._path.suffixes - - @property - def stem(self) -> str: - return self._path.stem - - async def absolute(self) -> Path: - path = await to_thread.run_sync(self._path.absolute) - return Path(path) - - def as_posix(self) -> str: - return self._path.as_posix() - - def as_uri(self) -> str: - return self._path.as_uri() - - if sys.version_info >= (3, 13): - parser: ClassVar[ModuleType] = pathlib.Path.parser - - @classmethod - def from_uri(cls, uri: str) -> Path: - return Path(pathlib.Path.from_uri(uri)) - - def full_match( - self, path_pattern: str, *, case_sensitive: bool | None = None - ) -> bool: - return self._path.full_match(path_pattern, case_sensitive=case_sensitive) - - def match( - self, path_pattern: str, *, case_sensitive: bool | None = None - ) -> bool: - return self._path.match(path_pattern, case_sensitive=case_sensitive) - else: - - def match(self, path_pattern: str) -> bool: - return self._path.match(path_pattern) - - if sys.version_info >= (3, 14): - - @property - def info(self) -> Any: # TODO: add return type annotation when Typeshed gets it - return self._path.info - - async def copy( - self, - target: str | os.PathLike[str], - *, - follow_symlinks: bool = True, - preserve_metadata: bool = False, - ) -> Path: - func = partial( - self._path.copy, - follow_symlinks=follow_symlinks, - preserve_metadata=preserve_metadata, - ) - return Path(await to_thread.run_sync(func, pathlib.Path(target))) - - async def copy_into( - self, - target_dir: str | os.PathLike[str], - *, - follow_symlinks: bool = True, - preserve_metadata: bool = False, - ) -> Path: - func = partial( - self._path.copy_into, - follow_symlinks=follow_symlinks, - preserve_metadata=preserve_metadata, - ) - return Path(await to_thread.run_sync(func, pathlib.Path(target_dir))) - - async def move(self, target: str | os.PathLike[str]) -> Path: - # Upstream does not handle anyio.Path properly as a PathLike - target = pathlib.Path(target) - return Path(await to_thread.run_sync(self._path.move, target)) - - async def move_into( - self, - target_dir: str | os.PathLike[str], - ) -> Path: - return Path(await to_thread.run_sync(self._path.move_into, target_dir)) - - def is_relative_to(self, other: str | PathLike[str]) -> bool: - try: - self.relative_to(other) - return True - except ValueError: - return False - - async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None: - func = partial(os.chmod, follow_symlinks=follow_symlinks) - return await to_thread.run_sync(func, self._path, mode) - - @classmethod - async def cwd(cls) -> Path: - path = await to_thread.run_sync(pathlib.Path.cwd) - return cls(path) - - async def exists(self) -> bool: - return await to_thread.run_sync(self._path.exists, abandon_on_cancel=True) - - async def expanduser(self) -> Path: - return Path( - await to_thread.run_sync(self._path.expanduser, abandon_on_cancel=True) - ) - - if sys.version_info < (3, 12): - # Python 3.11 and earlier - def glob(self, pattern: str) -> AsyncIterator[Path]: - gen = self._path.glob(pattern) - return _PathIterator(gen) - elif (3, 12) <= sys.version_info < (3, 13): - # changed in Python 3.12: - # - The case_sensitive parameter was added. - def glob( - self, - pattern: str, - *, - case_sensitive: bool | None = None, - ) -> AsyncIterator[Path]: - gen = self._path.glob(pattern, case_sensitive=case_sensitive) - return _PathIterator(gen) - elif sys.version_info >= (3, 13): - # Changed in Python 3.13: - # - The recurse_symlinks parameter was added. - # - The pattern parameter accepts a path-like object. - def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block - self, - pattern: str | PathLike[str], - *, - case_sensitive: bool | None = None, - recurse_symlinks: bool = False, - ) -> AsyncIterator[Path]: - gen = self._path.glob( - pattern, # type: ignore[arg-type] - case_sensitive=case_sensitive, - recurse_symlinks=recurse_symlinks, - ) - return _PathIterator(gen) - - async def group(self) -> str: - return await to_thread.run_sync(self._path.group, abandon_on_cancel=True) - - async def hardlink_to( - self, target: str | bytes | PathLike[str] | PathLike[bytes] - ) -> None: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(os.link, target, self) - - @classmethod - async def home(cls) -> Path: - home_path = await to_thread.run_sync(pathlib.Path.home) - return cls(home_path) - - def is_absolute(self) -> bool: - return self._path.is_absolute() - - async def is_block_device(self) -> bool: - return await to_thread.run_sync( - self._path.is_block_device, abandon_on_cancel=True - ) - - async def is_char_device(self) -> bool: - return await to_thread.run_sync( - self._path.is_char_device, abandon_on_cancel=True - ) - - async def is_dir(self) -> bool: - return await to_thread.run_sync(self._path.is_dir, abandon_on_cancel=True) - - async def is_fifo(self) -> bool: - return await to_thread.run_sync(self._path.is_fifo, abandon_on_cancel=True) - - async def is_file(self) -> bool: - return await to_thread.run_sync(self._path.is_file, abandon_on_cancel=True) - - if sys.version_info >= (3, 12): - - async def is_junction(self) -> bool: - return await to_thread.run_sync(self._path.is_junction) - - async def is_mount(self) -> bool: - return await to_thread.run_sync( - os.path.ismount, self._path, abandon_on_cancel=True - ) - - def is_reserved(self) -> bool: - return self._path.is_reserved() - - async def is_socket(self) -> bool: - return await to_thread.run_sync(self._path.is_socket, abandon_on_cancel=True) - - async def is_symlink(self) -> bool: - return await to_thread.run_sync(self._path.is_symlink, abandon_on_cancel=True) - - async def iterdir(self) -> AsyncIterator[Path]: - gen = ( - self._path.iterdir() - if sys.version_info < (3, 13) - else await to_thread.run_sync(self._path.iterdir, abandon_on_cancel=True) - ) - async for path in _PathIterator(gen): - yield path - - def joinpath(self, *args: str | PathLike[str]) -> Path: - return Path(self._path.joinpath(*args)) - - async def lchmod(self, mode: int) -> None: - await to_thread.run_sync(self._path.lchmod, mode) - - async def lstat(self) -> os.stat_result: - return await to_thread.run_sync(self._path.lstat, abandon_on_cancel=True) - - async def mkdir( - self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False - ) -> None: - await to_thread.run_sync(self._path.mkdir, mode, parents, exist_ok) - - @overload - async def open( - self, - mode: OpenBinaryMode, - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - ) -> AsyncFile[bytes]: ... - - @overload - async def open( - self, - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - ) -> AsyncFile[str]: ... - - async def open( - self, - mode: str = "r", - buffering: int = -1, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - ) -> AsyncFile[Any]: - fp = await to_thread.run_sync( - self._path.open, mode, buffering, encoding, errors, newline - ) - return AsyncFile(fp) - - async def owner(self) -> str: - return await to_thread.run_sync(self._path.owner, abandon_on_cancel=True) - - async def read_bytes(self) -> bytes: - return await to_thread.run_sync(self._path.read_bytes) - - async def read_text( - self, encoding: str | None = None, errors: str | None = None - ) -> str: - return await to_thread.run_sync(self._path.read_text, encoding, errors) - - if sys.version_info >= (3, 12): - - def relative_to( - self, *other: str | PathLike[str], walk_up: bool = False - ) -> Path: - # relative_to() should work with any PathLike but it doesn't - others = [pathlib.Path(other) for other in other] - return Path(self._path.relative_to(*others, walk_up=walk_up)) - - else: - - def relative_to(self, *other: str | PathLike[str]) -> Path: - return Path(self._path.relative_to(*other)) - - async def readlink(self) -> Path: - target = await to_thread.run_sync(os.readlink, self._path) - return Path(target) - - async def rename(self, target: str | pathlib.PurePath | Path) -> Path: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.rename, target) - return Path(target) - - async def replace(self, target: str | pathlib.PurePath | Path) -> Path: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.replace, target) - return Path(target) - - async def resolve(self, strict: bool = False) -> Path: - func = partial(self._path.resolve, strict=strict) - return Path(await to_thread.run_sync(func, abandon_on_cancel=True)) - - if sys.version_info < (3, 12): - # Pre Python 3.12 - def rglob(self, pattern: str) -> AsyncIterator[Path]: - gen = self._path.rglob(pattern) - return _PathIterator(gen) - elif (3, 12) <= sys.version_info < (3, 13): - # Changed in Python 3.12: - # - The case_sensitive parameter was added. - def rglob( - self, pattern: str, *, case_sensitive: bool | None = None - ) -> AsyncIterator[Path]: - gen = self._path.rglob(pattern, case_sensitive=case_sensitive) - return _PathIterator(gen) - elif sys.version_info >= (3, 13): - # Changed in Python 3.13: - # - The recurse_symlinks parameter was added. - # - The pattern parameter accepts a path-like object. - def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block - self, - pattern: str | PathLike[str], - *, - case_sensitive: bool | None = None, - recurse_symlinks: bool = False, - ) -> AsyncIterator[Path]: - gen = self._path.rglob( - pattern, # type: ignore[arg-type] - case_sensitive=case_sensitive, - recurse_symlinks=recurse_symlinks, - ) - return _PathIterator(gen) - - async def rmdir(self) -> None: - await to_thread.run_sync(self._path.rmdir) - - async def samefile(self, other_path: str | PathLike[str]) -> bool: - if isinstance(other_path, Path): - other_path = other_path._path - - return await to_thread.run_sync( - self._path.samefile, other_path, abandon_on_cancel=True - ) - - async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result: - func = partial(os.stat, follow_symlinks=follow_symlinks) - return await to_thread.run_sync(func, self._path, abandon_on_cancel=True) - - async def symlink_to( - self, - target: str | bytes | PathLike[str] | PathLike[bytes], - target_is_directory: bool = False, - ) -> None: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.symlink_to, target, target_is_directory) - - async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None: - await to_thread.run_sync(self._path.touch, mode, exist_ok) - - async def unlink(self, missing_ok: bool = False) -> None: - try: - await to_thread.run_sync(self._path.unlink) - except FileNotFoundError: - if not missing_ok: - raise - - if sys.version_info >= (3, 12): - - async def walk( - self, - top_down: bool = True, - on_error: Callable[[OSError], object] | None = None, - follow_symlinks: bool = False, - ) -> AsyncIterator[tuple[Path, list[str], list[str]]]: - def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None: - try: - return next(gen) - except StopIteration: - return None - - gen = self._path.walk(top_down, on_error, follow_symlinks) - while True: - value = await to_thread.run_sync(get_next_value) - if value is None: - return - - root, dirs, paths = value - yield Path(root), dirs, paths - - def with_name(self, name: str) -> Path: - return Path(self._path.with_name(name)) - - def with_stem(self, stem: str) -> Path: - return Path(self._path.with_name(stem + self._path.suffix)) - - def with_suffix(self, suffix: str) -> Path: - return Path(self._path.with_suffix(suffix)) - - def with_segments(self, *pathsegments: str | PathLike[str]) -> Path: - return Path(*pathsegments) - - async def write_bytes(self, data: bytes) -> int: - return await to_thread.run_sync(self._path.write_bytes, data) - - async def write_text( - self, - data: str, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - ) -> int: - # Path.write_text() does not support the "newline" parameter before Python 3.10 - def sync_write_text() -> int: - with self._path.open( - "w", encoding=encoding, errors=errors, newline=newline - ) as fp: - return fp.write(data) - - return await to_thread.run_sync(sync_write_text) - - -PathLike.register(Path) diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_resources.py b/venv/lib/python3.10/site-packages/anyio/_core/_resources.py deleted file mode 100644 index b9a5344aef2962670f9b305a02cd0b11f2087d2f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_resources.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import annotations - -from ..abc import AsyncResource -from ._tasks import CancelScope - - -async def aclose_forcefully(resource: AsyncResource) -> None: - """ - Close an asynchronous resource in a cancelled scope. - - Doing this closes the resource without waiting on anything. - - :param resource: the resource to close - - """ - with CancelScope() as scope: - scope.cancel() - await resource.aclose() diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_signals.py b/venv/lib/python3.10/site-packages/anyio/_core/_signals.py deleted file mode 100644 index e24c79e10d4b76775679f7dd0dbe3f5860150451..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_signals.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -from collections.abc import AsyncIterator -from contextlib import AbstractContextManager -from signal import Signals - -from ._eventloop import get_async_backend - - -def open_signal_receiver( - *signals: Signals, -) -> AbstractContextManager[AsyncIterator[Signals]]: - """ - Start receiving operating system signals. - - :param signals: signals to receive (e.g. ``signal.SIGINT``) - :return: an asynchronous context manager for an asynchronous iterator which yields - signal numbers - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. warning:: Windows does not support signals natively so it is best to avoid - relying on this in cross-platform applications. - - .. warning:: On asyncio, this permanently replaces any previous signal handler for - the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`. - - """ - return get_async_backend().open_signal_receiver(*signals) diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_sockets.py b/venv/lib/python3.10/site-packages/anyio/_core/_sockets.py deleted file mode 100644 index 6c99b3a1c1c7a5beee07aa5cf053149f8b5b9e2f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_sockets.py +++ /dev/null @@ -1,1003 +0,0 @@ -from __future__ import annotations - -import errno -import os -import socket -import ssl -import stat -import sys -from collections.abc import Awaitable -from dataclasses import dataclass -from ipaddress import IPv4Address, IPv6Address, ip_address -from os import PathLike, chmod -from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, Literal, cast, overload - -from .. import ConnectionFailed, to_thread -from ..abc import ( - ByteStreamConnectable, - ConnectedUDPSocket, - ConnectedUNIXDatagramSocket, - IPAddressType, - IPSockAddrType, - SocketListener, - SocketStream, - UDPSocket, - UNIXDatagramSocket, - UNIXSocketStream, -) -from ..streams.stapled import MultiListener -from ..streams.tls import TLSConnectable, TLSStream -from ._eventloop import get_async_backend -from ._resources import aclose_forcefully -from ._synchronization import Event -from ._tasks import create_task_group, move_on_after - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike -else: - FileDescriptorLike = object - -if sys.version_info < (3, 11): - from exceptiongroup import ExceptionGroup - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - -if sys.version_info < (3, 13): - from typing_extensions import deprecated -else: - from warnings import deprecated - -IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515 - -AnyIPAddressFamily = Literal[ - AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6 -] -IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6] - - -# tls_hostname given -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str, - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# ssl_context given -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - ssl_context: ssl.SSLContext, - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# tls=True -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - tls: Literal[True], - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# tls=False -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - tls: Literal[False], - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> SocketStream: ... - - -# No TLS arguments -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - happy_eyeballs_delay: float = ..., -) -> SocketStream: ... - - -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = None, - tls: bool = False, - ssl_context: ssl.SSLContext | None = None, - tls_standard_compatible: bool = True, - tls_hostname: str | None = None, - happy_eyeballs_delay: float = 0.25, -) -> SocketStream | TLSStream: - """ - Connect to a host using the TCP protocol. - - This function implements the stateless version of the Happy Eyeballs algorithm (RFC - 6555). If ``remote_host`` is a host name that resolves to multiple IP addresses, - each one is tried until one connection attempt succeeds. If the first attempt does - not connected within 250 milliseconds, a second attempt is started using the next - address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if - available) is tried first. - - When the connection has been established, a TLS handshake will be done if either - ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``. - - :param remote_host: the IP address or host name to connect to - :param remote_port: port on the target host to connect to - :param local_host: the interface address or name to bind the socket to before - connecting - :param tls: ``True`` to do a TLS handshake with the connected stream and return a - :class:`~anyio.streams.tls.TLSStream` instead - :param ssl_context: the SSL context object to use (if omitted, a default context is - created) - :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake - before closing the stream and requires that the server does this as well. - Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream. - Some protocols, such as HTTP, require this option to be ``False``. - See :meth:`~ssl.SSLContext.wrap_socket` for details. - :param tls_hostname: host name to check the server certificate against (defaults to - the value of ``remote_host``) - :param happy_eyeballs_delay: delay (in seconds) before starting the next connection - attempt - :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream - :raises ConnectionFailed: if the connection fails - - """ - # Placed here due to https://github.com/python/mypy/issues/7057 - connected_stream: SocketStream | None = None - - async def try_connect(remote_host: str, event: Event) -> None: - nonlocal connected_stream - try: - stream = await asynclib.connect_tcp(remote_host, remote_port, local_address) - except OSError as exc: - oserrors.append(exc) - return - else: - if connected_stream is None: - connected_stream = stream - tg.cancel_scope.cancel() - else: - await stream.aclose() - finally: - event.set() - - asynclib = get_async_backend() - local_address: IPSockAddrType | None = None - family = socket.AF_UNSPEC - if local_host: - gai_res = await getaddrinfo(str(local_host), None) - family, *_, local_address = gai_res[0] - - target_host = str(remote_host) - try: - addr_obj = ip_address(remote_host) - except ValueError: - addr_obj = None - - if addr_obj is not None: - if isinstance(addr_obj, IPv6Address): - target_addrs = [(socket.AF_INET6, addr_obj.compressed)] - else: - target_addrs = [(socket.AF_INET, addr_obj.compressed)] - else: - # getaddrinfo() will raise an exception if name resolution fails - gai_res = await getaddrinfo( - target_host, remote_port, family=family, type=socket.SOCK_STREAM - ) - - # Organize the list so that the first address is an IPv6 address (if available) - # and the second one is an IPv4 addresses. The rest can be in whatever order. - v6_found = v4_found = False - target_addrs = [] - for af, *_, sa in gai_res: - if af == socket.AF_INET6 and not v6_found: - v6_found = True - target_addrs.insert(0, (af, sa[0])) - elif af == socket.AF_INET and not v4_found and v6_found: - v4_found = True - target_addrs.insert(1, (af, sa[0])) - else: - target_addrs.append((af, sa[0])) - - oserrors: list[OSError] = [] - try: - async with create_task_group() as tg: - for _af, addr in target_addrs: - event = Event() - tg.start_soon(try_connect, addr, event) - with move_on_after(happy_eyeballs_delay): - await event.wait() - - if connected_stream is None: - cause = ( - oserrors[0] - if len(oserrors) == 1 - else ExceptionGroup("multiple connection attempts failed", oserrors) - ) - raise OSError("All connection attempts failed") from cause - finally: - oserrors.clear() - - if tls or tls_hostname or ssl_context: - try: - return await TLSStream.wrap( - connected_stream, - server_side=False, - hostname=tls_hostname or str(remote_host), - ssl_context=ssl_context, - standard_compatible=tls_standard_compatible, - ) - except BaseException: - await aclose_forcefully(connected_stream) - raise - - return connected_stream - - -async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream: - """ - Connect to the given UNIX socket. - - Not available on Windows. - - :param path: path to the socket - :return: a socket stream object - :raises ConnectionFailed: if the connection fails - - """ - path = os.fspath(path) - return await get_async_backend().connect_unix(path) - - -async def create_tcp_listener( - *, - local_host: IPAddressType | None = None, - local_port: int = 0, - family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC, - backlog: int = 65536, - reuse_port: bool = False, -) -> MultiListener[SocketStream]: - """ - Create a TCP socket listener. - - :param local_port: port number to listen on - :param local_host: IP address of the interface to listen on. If omitted, listen on - all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address - family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6. - :param family: address family (used if ``local_host`` was omitted) - :param backlog: maximum number of queued incoming connections (up to a maximum of - 2**16, or 65536) - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a multi-listener object containing one or more socket listeners - :raises OSError: if there's an error creating a socket, or binding to one or more - interfaces failed - - """ - asynclib = get_async_backend() - backlog = min(backlog, 65536) - local_host = str(local_host) if local_host is not None else None - - def setup_raw_socket( - fam: AddressFamily, - bind_addr: tuple[str, int] | tuple[str, int, int, int], - *, - v6only: bool = True, - ) -> socket.socket: - sock = socket.socket(fam) - try: - sock.setblocking(False) - - if fam == AddressFamily.AF_INET6: - sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only) - - # For Windows, enable exclusive address use. For others, enable address - # reuse. - if sys.platform == "win32": - sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) - else: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - if reuse_port: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - - # Workaround for #554 - if fam == socket.AF_INET6 and "%" in bind_addr[0]: - addr, scope_id = bind_addr[0].split("%", 1) - bind_addr = (addr, bind_addr[1], 0, int(scope_id)) - - sock.bind(bind_addr) - sock.listen(backlog) - except BaseException: - sock.close() - raise - - return sock - - # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug - # where we don't get the correct scope ID for IPv6 link-local addresses when passing - # type=socket.SOCK_STREAM to getaddrinfo(): - # https://github.com/MagicStack/uvloop/issues/539 - gai_res = await getaddrinfo( - local_host, - local_port, - family=family, - type=socket.SOCK_STREAM if sys.platform == "win32" else 0, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - - # The set comprehension is here to work around a glibc bug: - # https://sourceware.org/bugzilla/show_bug.cgi?id=14969 - sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM}) - - # Special case for dual-stack binding on the "any" interface - if ( - local_host is None - and family == AddressFamily.AF_UNSPEC - and socket.has_dualstack_ipv6() - and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res) - ): - raw_socket = setup_raw_socket( - AddressFamily.AF_INET6, ("::", local_port), v6only=False - ) - listener = asynclib.create_tcp_listener(raw_socket) - return MultiListener([listener]) - - errors: list[OSError] = [] - try: - for _ in range(len(sockaddrs)): - listeners: list[SocketListener] = [] - bound_ephemeral_port = local_port - try: - for fam, *_, sockaddr in sockaddrs: - sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:] - raw_socket = setup_raw_socket(fam, sockaddr) - - # Store the assigned port if an ephemeral port was requested, so - # we'll bind to the same port on all interfaces - if local_port == 0 and len(gai_res) > 1: - bound_ephemeral_port = raw_socket.getsockname()[1] - - listeners.append(asynclib.create_tcp_listener(raw_socket)) - except BaseException as exc: - for listener in listeners: - await listener.aclose() - - # If an ephemeral port was requested but binding the assigned port - # failed for another interface, rotate the address list and try again - if ( - isinstance(exc, OSError) - and exc.errno == errno.EADDRINUSE - and local_port == 0 - and bound_ephemeral_port - ): - errors.append(exc) - sockaddrs.append(sockaddrs.pop(0)) - continue - - raise - - return MultiListener(listeners) - - raise OSError( - f"Could not create {len(sockaddrs)} listeners with a consistent port" - ) from ExceptionGroup("Several bind attempts failed", errors) - finally: - del errors # Prevent reference cycles - - -async def create_unix_listener( - path: str | bytes | PathLike[Any], - *, - mode: int | None = None, - backlog: int = 65536, -) -> SocketListener: - """ - Create a UNIX socket listener. - - Not available on Windows. - - :param path: path of the socket - :param mode: permissions to set on the socket - :param backlog: maximum number of queued incoming connections (up to a maximum of - 2**16, or 65536) - :return: a listener object - - .. versionchanged:: 3.0 - If a socket already exists on the file system in the given path, it will be - removed first. - - """ - backlog = min(backlog, 65536) - raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM) - try: - raw_socket.listen(backlog) - return get_async_backend().create_unix_listener(raw_socket) - except BaseException: - raw_socket.close() - raise - - -async def create_udp_socket( - family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, - *, - local_host: IPAddressType | None = None, - local_port: int = 0, - reuse_port: bool = False, -) -> UDPSocket: - """ - Create a UDP socket. - - If ``port`` has been given, the socket will be bound to this port on the local - machine, making this socket suitable for providing UDP based services. - - :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically - determined from ``local_host`` if omitted - :param local_host: IP address or host name of the local interface to bind to - :param local_port: local port to bind to - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a UDP socket - - """ - if family is AddressFamily.AF_UNSPEC and not local_host: - raise ValueError('Either "family" or "local_host" must be given') - - if local_host: - gai_res = await getaddrinfo( - str(local_host), - local_port, - family=family, - type=socket.SOCK_DGRAM, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - local_address = gai_res[0][-1] - elif family is AddressFamily.AF_INET6: - local_address = ("::", 0) - else: - local_address = ("0.0.0.0", 0) - - sock = await get_async_backend().create_udp_socket( - family, local_address, None, reuse_port - ) - return cast(UDPSocket, sock) - - -async def create_connected_udp_socket( - remote_host: IPAddressType, - remote_port: int, - *, - family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, - local_host: IPAddressType | None = None, - local_port: int = 0, - reuse_port: bool = False, -) -> ConnectedUDPSocket: - """ - Create a connected UDP socket. - - Connected UDP sockets can only communicate with the specified remote host/port, an - any packets sent from other sources are dropped. - - :param remote_host: remote host to set as the default target - :param remote_port: port on the remote host to set as the default target - :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically - determined from ``local_host`` or ``remote_host`` if omitted - :param local_host: IP address or host name of the local interface to bind to - :param local_port: local port to bind to - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a connected UDP socket - - """ - local_address = None - if local_host: - gai_res = await getaddrinfo( - str(local_host), - local_port, - family=family, - type=socket.SOCK_DGRAM, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - local_address = gai_res[0][-1] - - gai_res = await getaddrinfo( - str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - remote_address = gai_res[0][-1] - - sock = await get_async_backend().create_udp_socket( - family, local_address, remote_address, reuse_port - ) - return cast(ConnectedUDPSocket, sock) - - -async def create_unix_datagram_socket( - *, - local_path: None | str | bytes | PathLike[Any] = None, - local_mode: int | None = None, -) -> UNIXDatagramSocket: - """ - Create a UNIX datagram socket. - - Not available on Windows. - - If ``local_path`` has been given, the socket will be bound to this path, making this - socket suitable for receiving datagrams from other processes. Other processes can - send datagrams to this socket only if ``local_path`` is set. - - If a socket already exists on the file system in the ``local_path``, it will be - removed first. - - :param local_path: the path on which to bind to - :param local_mode: permissions to set on the local socket - :return: a UNIX datagram socket - - """ - raw_socket = await setup_unix_local_socket( - local_path, local_mode, socket.SOCK_DGRAM - ) - return await get_async_backend().create_unix_datagram_socket(raw_socket, None) - - -async def create_connected_unix_datagram_socket( - remote_path: str | bytes | PathLike[Any], - *, - local_path: None | str | bytes | PathLike[Any] = None, - local_mode: int | None = None, -) -> ConnectedUNIXDatagramSocket: - """ - Create a connected UNIX datagram socket. - - Connected datagram sockets can only communicate with the specified remote path. - - If ``local_path`` has been given, the socket will be bound to this path, making - this socket suitable for receiving datagrams from other processes. Other processes - can send datagrams to this socket only if ``local_path`` is set. - - If a socket already exists on the file system in the ``local_path``, it will be - removed first. - - :param remote_path: the path to set as the default target - :param local_path: the path on which to bind to - :param local_mode: permissions to set on the local socket - :return: a connected UNIX datagram socket - - """ - remote_path = os.fspath(remote_path) - raw_socket = await setup_unix_local_socket( - local_path, local_mode, socket.SOCK_DGRAM - ) - return await get_async_backend().create_unix_datagram_socket( - raw_socket, remote_path - ) - - -async def getaddrinfo( - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, -) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]: - """ - Look up a numeric IP address given a host name. - - Internationalized domain names are translated according to the (non-transitional) - IDNA 2008 standard. - - .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of - (host, port), unlike what :func:`socket.getaddrinfo` does. - - :param host: host name - :param port: port number - :param family: socket family (`'AF_INET``, ...) - :param type: socket type (``SOCK_STREAM``, ...) - :param proto: protocol number - :param flags: flags to pass to upstream ``getaddrinfo()`` - :return: list of tuples containing (family, type, proto, canonname, sockaddr) - - .. seealso:: :func:`socket.getaddrinfo` - - """ - # Handle unicode hostnames - if isinstance(host, str): - try: - encoded_host: bytes | None = host.encode("ascii") - except UnicodeEncodeError: - import idna - - encoded_host = idna.encode(host, uts46=True) - else: - encoded_host = host - - gai_res = await get_async_backend().getaddrinfo( - encoded_host, port, family=family, type=type, proto=proto, flags=flags - ) - return [ - (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr)) - for family, type, proto, canonname, sockaddr in gai_res - # filter out IPv6 results when IPv6 is disabled - if not isinstance(sockaddr[0], int) - ] - - -def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]: - """ - Look up the host name of an IP address. - - :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4) - :param flags: flags to pass to upstream ``getnameinfo()`` - :return: a tuple of (host name, service name) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. seealso:: :func:`socket.getnameinfo` - - """ - return get_async_backend().getnameinfo(sockaddr, flags) - - -@deprecated("This function is deprecated; use `wait_readable` instead") -def wait_socket_readable(sock: socket.socket) -> Awaitable[None]: - """ - .. deprecated:: 4.7.0 - Use :func:`wait_readable` instead. - - Wait until the given socket has data to be read. - - .. warning:: Only use this on raw sockets that have not been wrapped by any higher - level constructs like socket streams! - - :param sock: a socket object - :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the - socket to become readable - :raises ~anyio.BusyResourceError: if another task is already waiting for the socket - to become readable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_readable(sock.fileno()) - - -@deprecated("This function is deprecated; use `wait_writable` instead") -def wait_socket_writable(sock: socket.socket) -> Awaitable[None]: - """ - .. deprecated:: 4.7.0 - Use :func:`wait_writable` instead. - - Wait until the given socket can be written to. - - This does **NOT** work on Windows when using the asyncio backend with a proactor - event loop (default on py3.8+). - - .. warning:: Only use this on raw sockets that have not been wrapped by any higher - level constructs like socket streams! - - :param sock: a socket object - :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the - socket to become writable - :raises ~anyio.BusyResourceError: if another task is already waiting for the socket - to become writable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_writable(sock.fileno()) - - -def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]: - """ - Wait until the given object has data to be read. - - On Unix systems, ``obj`` must either be an integer file descriptor, or else an - object with a ``.fileno()`` method which returns an integer file descriptor. Any - kind of file descriptor can be passed, though the exact semantics will depend on - your kernel. For example, this probably won't do anything useful for on-disk files. - - On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an - object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File - descriptors aren't supported, and neither are handles that refer to anything besides - a ``SOCKET``. - - On backends where this functionality is not natively provided (asyncio - ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread - which is set to shut down when the interpreter shuts down. - - .. warning:: Don't use this on raw sockets that have been wrapped by any higher - level constructs like socket streams! - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the - object to become readable - :raises ~anyio.BusyResourceError: if another task is already waiting for the object - to become readable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_readable(obj) - - -def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]: - """ - Wait until the given object can be written to. - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the - object to become writable - :raises ~anyio.BusyResourceError: if another task is already waiting for the object - to become writable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. seealso:: See the documentation of :func:`wait_readable` for the definition of - ``obj`` and notes on backend compatibility. - - .. warning:: Don't use this on raw sockets that have been wrapped by any higher - level constructs like socket streams! - - """ - return get_async_backend().wait_writable(obj) - - -def notify_closing(obj: FileDescriptorLike) -> None: - """ - Call this before closing a file descriptor (on Unix) or socket (on - Windows). This will cause any `wait_readable` or `wait_writable` - calls on the given object to immediately wake up and raise - `~anyio.ClosedResourceError`. - - This doesn't actually close the object – you still have to do that - yourself afterwards. Also, you want to be careful to make sure no - new tasks start waiting on the object in between when you call this - and when it's actually closed. So to close something properly, you - usually want to do these steps in order: - - 1. Explicitly mark the object as closed, so that any new attempts - to use it will abort before they start. - 2. Call `notify_closing` to wake up any already-existing users. - 3. Actually close the object. - - It's also possible to do them in a different order if that's more - convenient, *but only if* you make sure not to have any checkpoints in - between the steps. This way they all happen in a single atomic - step, so other tasks won't be able to tell what order they happened - in anyway. - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - get_async_backend().notify_closing(obj) - - -# -# Private API -# - - -def convert_ipv6_sockaddr( - sockaddr: tuple[str, int, int, int] | tuple[str, int], -) -> tuple[str, int]: - """ - Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format. - - If the scope ID is nonzero, it is added to the address, separated with ``%``. - Otherwise the flow id and scope id are simply cut off from the tuple. - Any other kinds of socket addresses are returned as-is. - - :param sockaddr: the result of :meth:`~socket.socket.getsockname` - :return: the converted socket address - - """ - # This is more complicated than it should be because of MyPy - if isinstance(sockaddr, tuple) and len(sockaddr) == 4: - host, port, flowinfo, scope_id = sockaddr - if scope_id: - # PyPy (as of v7.3.11) leaves the interface name in the result, so - # we discard it and only get the scope ID from the end - # (https://foss.heptapod.net/pypy/pypy/-/issues/3938) - host = host.split("%")[0] - - # Add scope_id to the address - return f"{host}%{scope_id}", port - else: - return host, port - else: - return sockaddr - - -async def setup_unix_local_socket( - path: None | str | bytes | PathLike[Any], - mode: int | None, - socktype: int, -) -> socket.socket: - """ - Create a UNIX local socket object, deleting the socket at the given path if it - exists. - - Not available on Windows. - - :param path: path of the socket - :param mode: permissions to set on the socket - :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM - - """ - path_str: str | None - if path is not None: - path_str = os.fsdecode(path) - - # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call - if not path_str.startswith("\0"): - # Copied from pathlib... - try: - stat_result = os.stat(path) - except OSError as e: - if e.errno not in ( - errno.ENOENT, - errno.ENOTDIR, - errno.EBADF, - errno.ELOOP, - ): - raise - else: - if stat.S_ISSOCK(stat_result.st_mode): - os.unlink(path) - else: - path_str = None - - raw_socket = socket.socket(socket.AF_UNIX, socktype) - raw_socket.setblocking(False) - - if path_str is not None: - try: - await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True) - if mode is not None: - await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True) - except BaseException: - raw_socket.close() - raise - - return raw_socket - - -@dataclass -class TCPConnectable(ByteStreamConnectable): - """ - Connects to a TCP server at the given host and port. - - :param host: host name or IP address of the server - :param port: TCP port number of the server - """ - - host: str | IPv4Address | IPv6Address - port: int - - def __post_init__(self) -> None: - if self.port < 1 or self.port > 65535: - raise ValueError("TCP port number out of range") - - @override - async def connect(self) -> SocketStream: - try: - return await connect_tcp(self.host, self.port) - except OSError as exc: - raise ConnectionFailed( - f"error connecting to {self.host}:{self.port}: {exc}" - ) from exc - - -@dataclass -class UNIXConnectable(ByteStreamConnectable): - """ - Connects to a UNIX domain socket at the given path. - - :param path: the file system path of the socket - """ - - path: str | bytes | PathLike[str] | PathLike[bytes] - - @override - async def connect(self) -> UNIXSocketStream: - try: - return await connect_unix(self.path) - except OSError as exc: - raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc - - -def as_connectable( - remote: ByteStreamConnectable - | tuple[str | IPv4Address | IPv6Address, int] - | str - | bytes - | PathLike[str], - /, - *, - tls: bool = False, - ssl_context: ssl.SSLContext | None = None, - tls_hostname: str | None = None, - tls_standard_compatible: bool = True, -) -> ByteStreamConnectable: - """ - Return a byte stream connectable from the given object. - - If a bytestream connectable is given, it is returned unchanged. - If a tuple of (host, port) is given, a TCP connectable is returned. - If a string or bytes path is given, a UNIX connectable is returned. - - If ``tls=True``, the connectable will be wrapped in a - :class:`~.streams.tls.TLSConnectable`. - - :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket - :param tls: if ``True``, wrap the plaintext connectable in a - :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings) - :param ssl_context: if ``tls=True``, the SSLContext object to use (if not provided, - a secure default will be created) - :param tls_hostname: if ``tls=True``, host name of the server to use for checking - the server certificate (defaults to the host portion of the address for TCP - connectables) - :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream - skip the closing handshake when closing the connection, so it won't raise an - exception if the server does the same - - """ - connectable: TCPConnectable | UNIXConnectable | TLSConnectable - if isinstance(remote, ByteStreamConnectable): - return remote - elif isinstance(remote, tuple) and len(remote) == 2: - connectable = TCPConnectable(*remote) - elif isinstance(remote, (str, bytes, PathLike)): - connectable = UNIXConnectable(remote) - else: - raise TypeError(f"cannot convert {remote!r} to a connectable") - - if tls: - if not tls_hostname and isinstance(connectable, TCPConnectable): - tls_hostname = str(connectable.host) - - connectable = TLSConnectable( - connectable, - ssl_context=ssl_context, - hostname=tls_hostname, - standard_compatible=tls_standard_compatible, - ) - - return connectable diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_streams.py b/venv/lib/python3.10/site-packages/anyio/_core/_streams.py deleted file mode 100644 index 2b9c7df200f9520357503c754bcdea1c047bdda3..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_streams.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import annotations - -import math -from typing import TypeVar -from warnings import warn - -from ..streams.memory import ( - MemoryObjectReceiveStream, - MemoryObjectSendStream, - _MemoryObjectStreamState, -) - -T_Item = TypeVar("T_Item") - - -class create_memory_object_stream( - tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]], -): - """ - Create a memory object stream. - - The stream's item type can be annotated like - :func:`create_memory_object_stream[T_Item]`. - - :param max_buffer_size: number of items held in the buffer until ``send()`` starts - blocking - :param item_type: old way of marking the streams with the right generic type for - static typing (does nothing on AnyIO 4) - - .. deprecated:: 4.0 - Use ``create_memory_object_stream[YourItemType](...)`` instead. - :return: a tuple of (send stream, receive stream) - - """ - - def __new__( # type: ignore[misc] - cls, max_buffer_size: float = 0, item_type: object = None - ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]: - if max_buffer_size != math.inf and not isinstance(max_buffer_size, int): - raise ValueError("max_buffer_size must be either an integer or math.inf") - if max_buffer_size < 0: - raise ValueError("max_buffer_size cannot be negative") - if item_type is not None: - warn( - "The item_type argument has been deprecated in AnyIO 4.0. " - "Use create_memory_object_stream[YourItemType](...) instead.", - DeprecationWarning, - stacklevel=2, - ) - - state = _MemoryObjectStreamState[T_Item](max_buffer_size) - return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state)) diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_subprocesses.py b/venv/lib/python3.10/site-packages/anyio/_core/_subprocesses.py deleted file mode 100644 index 36d9b306c992b83a8033c0ee66daa141d23d010c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_subprocesses.py +++ /dev/null @@ -1,202 +0,0 @@ -from __future__ import annotations - -import sys -from collections.abc import AsyncIterable, Iterable, Mapping, Sequence -from io import BytesIO -from os import PathLike -from subprocess import PIPE, CalledProcessError, CompletedProcess -from typing import IO, Any, Union, cast - -from ..abc import Process -from ._eventloop import get_async_backend -from ._tasks import create_task_group - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"] - - -async def run_process( - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - input: bytes | None = None, - stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = PIPE, - stderr: int | IO[Any] | None = PIPE, - check: bool = True, - cwd: StrOrBytesPath | None = None, - env: Mapping[str, str] | None = None, - startupinfo: Any = None, - creationflags: int = 0, - start_new_session: bool = False, - pass_fds: Sequence[int] = (), - user: str | int | None = None, - group: str | int | None = None, - extra_groups: Iterable[str | int] | None = None, - umask: int = -1, -) -> CompletedProcess[bytes]: - """ - Run an external command in a subprocess and wait until it completes. - - .. seealso:: :func:`subprocess.run` - - :param command: either a string to pass to the shell, or an iterable of strings - containing the executable name or path and its arguments - :param input: bytes passed to the standard input of the subprocess - :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or `None`; ``input`` overrides this - :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or `None` - :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - :data:`subprocess.STDOUT`, a file-like object, or `None` - :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the - process terminates with a return code other than 0 - :param cwd: If not ``None``, change the working directory to this before running the - command - :param env: if not ``None``, this mapping replaces the inherited environment - variables from the parent process - :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used - to specify process startup parameters (Windows only) - :param creationflags: flags that can be used to control the creation of the - subprocess (see :class:`subprocess.Popen` for the specifics) - :param start_new_session: if ``true`` the setsid() system call will be made in the - child process prior to the execution of the subprocess. (POSIX only) - :param pass_fds: sequence of file descriptors to keep open between the parent and - child processes. (POSIX only) - :param user: effective user to run the process as (Python >= 3.9, POSIX only) - :param group: effective group to run the process as (Python >= 3.9, POSIX only) - :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9, - POSIX only) - :param umask: if not negative, this umask is applied in the child process before - running the given command (Python >= 3.9, POSIX only) - :return: an object representing the completed process - :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process - exits with a nonzero return code - - """ - - async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None: - buffer = BytesIO() - async for chunk in stream: - buffer.write(chunk) - - stream_contents[index] = buffer.getvalue() - - if stdin is not None and input is not None: - raise ValueError("only one of stdin and input is allowed") - - async with await open_process( - command, - stdin=PIPE if input else stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd, - env=env, - startupinfo=startupinfo, - creationflags=creationflags, - start_new_session=start_new_session, - pass_fds=pass_fds, - user=user, - group=group, - extra_groups=extra_groups, - umask=umask, - ) as process: - stream_contents: list[bytes | None] = [None, None] - async with create_task_group() as tg: - if process.stdout: - tg.start_soon(drain_stream, process.stdout, 0) - - if process.stderr: - tg.start_soon(drain_stream, process.stderr, 1) - - if process.stdin and input: - await process.stdin.send(input) - await process.stdin.aclose() - - await process.wait() - - output, errors = stream_contents - if check and process.returncode != 0: - raise CalledProcessError(cast(int, process.returncode), command, output, errors) - - return CompletedProcess(command, cast(int, process.returncode), output, errors) - - -async def open_process( - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None = PIPE, - stdout: int | IO[Any] | None = PIPE, - stderr: int | IO[Any] | None = PIPE, - cwd: StrOrBytesPath | None = None, - env: Mapping[str, str] | None = None, - startupinfo: Any = None, - creationflags: int = 0, - start_new_session: bool = False, - pass_fds: Sequence[int] = (), - user: str | int | None = None, - group: str | int | None = None, - extra_groups: Iterable[str | int] | None = None, - umask: int = -1, -) -> Process: - """ - Start an external command in a subprocess. - - .. seealso:: :class:`subprocess.Popen` - - :param command: either a string to pass to the shell, or an iterable of strings - containing the executable name or path and its arguments - :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a - file-like object, or ``None`` - :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or ``None`` - :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - :data:`subprocess.STDOUT`, a file-like object, or ``None`` - :param cwd: If not ``None``, the working directory is changed before executing - :param env: If env is not ``None``, it must be a mapping that defines the - environment variables for the new process - :param creationflags: flags that can be used to control the creation of the - subprocess (see :class:`subprocess.Popen` for the specifics) - :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used - to specify process startup parameters (Windows only) - :param start_new_session: if ``true`` the setsid() system call will be made in the - child process prior to the execution of the subprocess. (POSIX only) - :param pass_fds: sequence of file descriptors to keep open between the parent and - child processes. (POSIX only) - :param user: effective user to run the process as (POSIX only) - :param group: effective group to run the process as (POSIX only) - :param extra_groups: supplementary groups to set in the subprocess (POSIX only) - :param umask: if not negative, this umask is applied in the child process before - running the given command (POSIX only) - :return: an asynchronous process object - - """ - kwargs: dict[str, Any] = {} - if user is not None: - kwargs["user"] = user - - if group is not None: - kwargs["group"] = group - - if extra_groups is not None: - kwargs["extra_groups"] = group - - if umask >= 0: - kwargs["umask"] = umask - - return await get_async_backend().open_process( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd, - env=env, - startupinfo=startupinfo, - creationflags=creationflags, - start_new_session=start_new_session, - pass_fds=pass_fds, - **kwargs, - ) diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_synchronization.py b/venv/lib/python3.10/site-packages/anyio/_core/_synchronization.py deleted file mode 100644 index c0ef27a686f22f77d5ec3f404005e2805fa46a64..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_synchronization.py +++ /dev/null @@ -1,753 +0,0 @@ -from __future__ import annotations - -import math -from collections import deque -from collections.abc import Callable -from dataclasses import dataclass -from types import TracebackType -from typing import TypeVar - -from ..lowlevel import checkpoint_if_cancelled -from ._eventloop import get_async_backend -from ._exceptions import BusyResourceError, NoEventLoopError -from ._tasks import CancelScope -from ._testing import TaskInfo, get_current_task - -T = TypeVar("T") - - -@dataclass(frozen=True) -class EventStatistics: - """ - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait` - """ - - tasks_waiting: int - - -@dataclass(frozen=True) -class CapacityLimiterStatistics: - """ - :ivar int borrowed_tokens: number of tokens currently borrowed by tasks - :ivar float total_tokens: total number of available tokens - :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from - this limiter - :ivar int tasks_waiting: number of tasks waiting on - :meth:`~.CapacityLimiter.acquire` or - :meth:`~.CapacityLimiter.acquire_on_behalf_of` - """ - - borrowed_tokens: int - total_tokens: float - borrowers: tuple[object, ...] - tasks_waiting: int - - -@dataclass(frozen=True) -class LockStatistics: - """ - :ivar bool locked: flag indicating if this lock is locked or not - :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the - lock is not held by any task) - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire` - """ - - locked: bool - owner: TaskInfo | None - tasks_waiting: int - - -@dataclass(frozen=True) -class ConditionStatistics: - """ - :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait` - :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying - :class:`~.Lock` - """ - - tasks_waiting: int - lock_statistics: LockStatistics - - -@dataclass(frozen=True) -class SemaphoreStatistics: - """ - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire` - - """ - - tasks_waiting: int - - -class Event: - def __new__(cls) -> Event: - try: - return get_async_backend().create_event() - except NoEventLoopError: - return EventAdapter() - - def set(self) -> None: - """Set the flag, notifying all listeners.""" - raise NotImplementedError - - def is_set(self) -> bool: - """Return ``True`` if the flag is set, ``False`` if not.""" - raise NotImplementedError - - async def wait(self) -> None: - """ - Wait until the flag has been set. - - If the flag has already been set when this method is called, it returns - immediately. - - """ - raise NotImplementedError - - def statistics(self) -> EventStatistics: - """Return statistics about the current state of this event.""" - raise NotImplementedError - - -class EventAdapter(Event): - _internal_event: Event | None = None - _is_set: bool = False - - def __new__(cls) -> EventAdapter: - return object.__new__(cls) - - @property - def _event(self) -> Event: - if self._internal_event is None: - self._internal_event = get_async_backend().create_event() - if self._is_set: - self._internal_event.set() - - return self._internal_event - - def set(self) -> None: - if self._internal_event is None: - self._is_set = True - else: - self._event.set() - - def is_set(self) -> bool: - if self._internal_event is None: - return self._is_set - - return self._internal_event.is_set() - - async def wait(self) -> None: - await self._event.wait() - - def statistics(self) -> EventStatistics: - if self._internal_event is None: - return EventStatistics(tasks_waiting=0) - - return self._internal_event.statistics() - - -class Lock: - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - try: - return get_async_backend().create_lock(fast_acquire=fast_acquire) - except NoEventLoopError: - return LockAdapter(fast_acquire=fast_acquire) - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - async def acquire(self) -> None: - """Acquire the lock.""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire the lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - raise NotImplementedError - - def release(self) -> None: - """Release the lock.""" - raise NotImplementedError - - def locked(self) -> bool: - """Return True if the lock is currently held.""" - raise NotImplementedError - - def statistics(self) -> LockStatistics: - """ - Return statistics about the current state of this lock. - - .. versionadded:: 3.0 - """ - raise NotImplementedError - - -class LockAdapter(Lock): - _internal_lock: Lock | None = None - - def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False): - self._fast_acquire = fast_acquire - - @property - def _lock(self) -> Lock: - if self._internal_lock is None: - self._internal_lock = get_async_backend().create_lock( - fast_acquire=self._fast_acquire - ) - - return self._internal_lock - - async def __aenter__(self) -> None: - await self._lock.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self._internal_lock is not None: - self._internal_lock.release() - - async def acquire(self) -> None: - """Acquire the lock.""" - await self._lock.acquire() - - def acquire_nowait(self) -> None: - """ - Acquire the lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - self._lock.acquire_nowait() - - def release(self) -> None: - """Release the lock.""" - self._lock.release() - - def locked(self) -> bool: - """Return True if the lock is currently held.""" - return self._lock.locked() - - def statistics(self) -> LockStatistics: - """ - Return statistics about the current state of this lock. - - .. versionadded:: 3.0 - - """ - if self._internal_lock is None: - return LockStatistics(False, None, 0) - - return self._internal_lock.statistics() - - -class Condition: - _owner_task: TaskInfo | None = None - - def __init__(self, lock: Lock | None = None): - self._lock = lock or Lock() - self._waiters: deque[Event] = deque() - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - def _check_acquired(self) -> None: - if self._owner_task != get_current_task(): - raise RuntimeError("The current task is not holding the underlying lock") - - async def acquire(self) -> None: - """Acquire the underlying lock.""" - await self._lock.acquire() - self._owner_task = get_current_task() - - def acquire_nowait(self) -> None: - """ - Acquire the underlying lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - self._lock.acquire_nowait() - self._owner_task = get_current_task() - - def release(self) -> None: - """Release the underlying lock.""" - self._lock.release() - - def locked(self) -> bool: - """Return True if the lock is set.""" - return self._lock.locked() - - def notify(self, n: int = 1) -> None: - """Notify exactly n listeners.""" - self._check_acquired() - for _ in range(n): - try: - event = self._waiters.popleft() - except IndexError: - break - - event.set() - - def notify_all(self) -> None: - """Notify all the listeners.""" - self._check_acquired() - for event in self._waiters: - event.set() - - self._waiters.clear() - - async def wait(self) -> None: - """Wait for a notification.""" - await checkpoint_if_cancelled() - self._check_acquired() - event = Event() - self._waiters.append(event) - self.release() - try: - await event.wait() - except BaseException: - if not event.is_set(): - self._waiters.remove(event) - - raise - finally: - with CancelScope(shield=True): - await self.acquire() - - async def wait_for(self, predicate: Callable[[], T]) -> T: - """ - Wait until a predicate becomes true. - - :param predicate: a callable that returns a truthy value when the condition is - met - :return: the result of the predicate - - .. versionadded:: 4.11.0 - - """ - while not (result := predicate()): - await self.wait() - - return result - - def statistics(self) -> ConditionStatistics: - """ - Return statistics about the current state of this condition. - - .. versionadded:: 3.0 - """ - return ConditionStatistics(len(self._waiters), self._lock.statistics()) - - -class Semaphore: - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - try: - return get_async_backend().create_semaphore( - initial_value, max_value=max_value, fast_acquire=fast_acquire - ) - except NoEventLoopError: - return SemaphoreAdapter(initial_value, max_value=max_value) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ): - if not isinstance(initial_value, int): - raise TypeError("initial_value must be an integer") - if initial_value < 0: - raise ValueError("initial_value must be >= 0") - if max_value is not None: - if not isinstance(max_value, int): - raise TypeError("max_value must be an integer or None") - if max_value < initial_value: - raise ValueError( - "max_value must be equal to or higher than initial_value" - ) - - self._fast_acquire = fast_acquire - - async def __aenter__(self) -> Semaphore: - await self.acquire() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - async def acquire(self) -> None: - """Decrement the semaphore value, blocking if necessary.""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire the underlying lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - raise NotImplementedError - - def release(self) -> None: - """Increment the semaphore value.""" - raise NotImplementedError - - @property - def value(self) -> int: - """The current value of the semaphore.""" - raise NotImplementedError - - @property - def max_value(self) -> int | None: - """The maximum value of the semaphore.""" - raise NotImplementedError - - def statistics(self) -> SemaphoreStatistics: - """ - Return statistics about the current state of this semaphore. - - .. versionadded:: 3.0 - """ - raise NotImplementedError - - -class SemaphoreAdapter(Semaphore): - _internal_semaphore: Semaphore | None = None - - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> SemaphoreAdapter: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> None: - super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) - self._initial_value = initial_value - self._max_value = max_value - - @property - def _semaphore(self) -> Semaphore: - if self._internal_semaphore is None: - self._internal_semaphore = get_async_backend().create_semaphore( - self._initial_value, max_value=self._max_value - ) - - return self._internal_semaphore - - async def acquire(self) -> None: - await self._semaphore.acquire() - - def acquire_nowait(self) -> None: - self._semaphore.acquire_nowait() - - def release(self) -> None: - self._semaphore.release() - - @property - def value(self) -> int: - if self._internal_semaphore is None: - return self._initial_value - - return self._semaphore.value - - @property - def max_value(self) -> int | None: - return self._max_value - - def statistics(self) -> SemaphoreStatistics: - if self._internal_semaphore is None: - return SemaphoreStatistics(tasks_waiting=0) - - return self._semaphore.statistics() - - -class CapacityLimiter: - def __new__(cls, total_tokens: float) -> CapacityLimiter: - try: - return get_async_backend().create_capacity_limiter(total_tokens) - except NoEventLoopError: - return CapacityLimiterAdapter(total_tokens) - - async def __aenter__(self) -> None: - raise NotImplementedError - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - raise NotImplementedError - - @property - def total_tokens(self) -> float: - """ - The total number of tokens available for borrowing. - - This is a read-write property. If the total number of tokens is increased, the - proportionate number of tasks waiting on this limiter will be granted their - tokens. - - .. versionchanged:: 3.0 - The property is now writable. - .. versionchanged:: 4.12 - The value can now be set to 0. - - """ - raise NotImplementedError - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - raise NotImplementedError - - @property - def borrowed_tokens(self) -> int: - """The number of tokens that have currently been borrowed.""" - raise NotImplementedError - - @property - def available_tokens(self) -> float: - """The number of tokens currently available to be borrowed""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire a token for the current task without waiting for one to become - available. - - :raises ~anyio.WouldBlock: if there are no tokens available for borrowing - - """ - raise NotImplementedError - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - """ - Acquire a token without waiting for one to become available. - - :param borrower: the entity borrowing a token - :raises ~anyio.WouldBlock: if there are no tokens available for borrowing - - """ - raise NotImplementedError - - async def acquire(self) -> None: - """ - Acquire a token for the current task, waiting if necessary for one to become - available. - - """ - raise NotImplementedError - - async def acquire_on_behalf_of(self, borrower: object) -> None: - """ - Acquire a token, waiting if necessary for one to become available. - - :param borrower: the entity borrowing a token - - """ - raise NotImplementedError - - def release(self) -> None: - """ - Release the token held by the current task. - - :raises RuntimeError: if the current task has not borrowed a token from this - limiter. - - """ - raise NotImplementedError - - def release_on_behalf_of(self, borrower: object) -> None: - """ - Release the token held by the given borrower. - - :raises RuntimeError: if the borrower has not borrowed a token from this - limiter. - - """ - raise NotImplementedError - - def statistics(self) -> CapacityLimiterStatistics: - """ - Return statistics about the current state of this limiter. - - .. versionadded:: 3.0 - - """ - raise NotImplementedError - - -class CapacityLimiterAdapter(CapacityLimiter): - _internal_limiter: CapacityLimiter | None = None - - def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter: - return object.__new__(cls) - - def __init__(self, total_tokens: float) -> None: - self.total_tokens = total_tokens - - @property - def _limiter(self) -> CapacityLimiter: - if self._internal_limiter is None: - self._internal_limiter = get_async_backend().create_capacity_limiter( - self._total_tokens - ) - - return self._internal_limiter - - async def __aenter__(self) -> None: - await self._limiter.__aenter__() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - return await self._limiter.__aexit__(exc_type, exc_val, exc_tb) - - @property - def total_tokens(self) -> float: - if self._internal_limiter is None: - return self._total_tokens - - return self._internal_limiter.total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - if not isinstance(value, int) and value is not math.inf: - raise TypeError("total_tokens must be an int or math.inf") - elif value < 1: - raise ValueError("total_tokens must be >= 1") - - if self._internal_limiter is None: - self._total_tokens = value - return - - self._limiter.total_tokens = value - - @property - def borrowed_tokens(self) -> int: - if self._internal_limiter is None: - return 0 - - return self._internal_limiter.borrowed_tokens - - @property - def available_tokens(self) -> float: - if self._internal_limiter is None: - return self._total_tokens - - return self._internal_limiter.available_tokens - - def acquire_nowait(self) -> None: - self._limiter.acquire_nowait() - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - self._limiter.acquire_on_behalf_of_nowait(borrower) - - async def acquire(self) -> None: - await self._limiter.acquire() - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await self._limiter.acquire_on_behalf_of(borrower) - - def release(self) -> None: - self._limiter.release() - - def release_on_behalf_of(self, borrower: object) -> None: - self._limiter.release_on_behalf_of(borrower) - - def statistics(self) -> CapacityLimiterStatistics: - if self._internal_limiter is None: - return CapacityLimiterStatistics( - borrowed_tokens=0, - total_tokens=self.total_tokens, - borrowers=(), - tasks_waiting=0, - ) - - return self._internal_limiter.statistics() - - -class ResourceGuard: - """ - A context manager for ensuring that a resource is only used by a single task at a - time. - - Entering this context manager while the previous has not exited it yet will trigger - :exc:`BusyResourceError`. - - :param action: the action to guard against (visible in the :exc:`BusyResourceError` - when triggered, e.g. "Another task is already {action} this resource") - - .. versionadded:: 4.1 - """ - - __slots__ = "action", "_guarded" - - def __init__(self, action: str = "using"): - self.action: str = action - self._guarded = False - - def __enter__(self) -> None: - if self._guarded: - raise BusyResourceError(self.action) - - self._guarded = True - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._guarded = False diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_tasks.py b/venv/lib/python3.10/site-packages/anyio/_core/_tasks.py deleted file mode 100644 index 0688bfe960cf9747373c93e482a64d1369befa11..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_tasks.py +++ /dev/null @@ -1,173 +0,0 @@ -from __future__ import annotations - -import math -from collections.abc import Generator -from contextlib import contextmanager -from types import TracebackType - -from ..abc._tasks import TaskGroup, TaskStatus -from ._eventloop import get_async_backend - - -class _IgnoredTaskStatus(TaskStatus[object]): - def started(self, value: object = None) -> None: - pass - - -TASK_STATUS_IGNORED = _IgnoredTaskStatus() - - -class CancelScope: - """ - Wraps a unit of work that can be made separately cancellable. - - :param deadline: The time (clock value) when this scope is cancelled automatically - :param shield: ``True`` to shield the cancel scope from external cancellation - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - """ - - def __new__( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline) - - def cancel(self, reason: str | None = None) -> None: - """ - Cancel this scope immediately. - - :param reason: a message describing the reason for the cancellation - - """ - raise NotImplementedError - - @property - def deadline(self) -> float: - """ - The time (clock value) when this scope is cancelled automatically. - - Will be ``float('inf')`` if no timeout has been set. - - """ - raise NotImplementedError - - @deadline.setter - def deadline(self, value: float) -> None: - raise NotImplementedError - - @property - def cancel_called(self) -> bool: - """``True`` if :meth:`cancel` has been called.""" - raise NotImplementedError - - @property - def cancelled_caught(self) -> bool: - """ - ``True`` if this scope suppressed a cancellation exception it itself raised. - - This is typically used to check if any work was interrupted, or to see if the - scope was cancelled due to its deadline being reached. The value will, however, - only be ``True`` if the cancellation was triggered by the scope itself (and not - an outer scope). - - """ - raise NotImplementedError - - @property - def shield(self) -> bool: - """ - ``True`` if this scope is shielded from external cancellation. - - While a scope is shielded, it will not receive cancellations from outside. - - """ - raise NotImplementedError - - @shield.setter - def shield(self, value: bool) -> None: - raise NotImplementedError - - def __enter__(self) -> CancelScope: - raise NotImplementedError - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - raise NotImplementedError - - -@contextmanager -def fail_after( - delay: float | None, shield: bool = False -) -> Generator[CancelScope, None, None]: - """ - Create a context manager which raises a :class:`TimeoutError` if does not finish in - time. - - :param delay: maximum allowed time (in seconds) before raising the exception, or - ``None`` to disable the timeout - :param shield: ``True`` to shield the cancel scope from external cancellation - :return: a context manager that yields a cancel scope - :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\] - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - current_time = get_async_backend().current_time - deadline = (current_time() + delay) if delay is not None else math.inf - with get_async_backend().create_cancel_scope( - deadline=deadline, shield=shield - ) as cancel_scope: - yield cancel_scope - - if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline: - raise TimeoutError - - -def move_on_after(delay: float | None, shield: bool = False) -> CancelScope: - """ - Create a cancel scope with a deadline that expires after the given delay. - - :param delay: maximum allowed time (in seconds) before exiting the context block, or - ``None`` to disable the timeout - :param shield: ``True`` to shield the cancel scope from external cancellation - :return: a cancel scope - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - deadline = ( - (get_async_backend().current_time() + delay) if delay is not None else math.inf - ) - return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield) - - -def current_effective_deadline() -> float: - """ - Return the nearest deadline among all the cancel scopes effective for the current - task. - - :return: a clock value from the event loop's internal clock (or ``float('inf')`` if - there is no deadline in effect, or ``float('-inf')`` if the current scope has - been cancelled) - :rtype: float - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_effective_deadline() - - -def create_task_group() -> TaskGroup: - """ - Create a task group. - - :return: a task group - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().create_task_group() diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_tempfile.py b/venv/lib/python3.10/site-packages/anyio/_core/_tempfile.py deleted file mode 100644 index fbb6b14a9a8eae9dcaa66eb68ac36d2084617877..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_tempfile.py +++ /dev/null @@ -1,616 +0,0 @@ -from __future__ import annotations - -import os -import sys -import tempfile -from collections.abc import Iterable -from io import BytesIO, TextIOWrapper -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - AnyStr, - Generic, - overload, -) - -from .. import to_thread -from .._core._fileio import AsyncFile -from ..lowlevel import checkpoint_if_cancelled - -if TYPE_CHECKING: - from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer - - -class TemporaryFile(Generic[AnyStr]): - """ - An asynchronous temporary file that is automatically created and cleaned up. - - This class provides an asynchronous context manager interface to a temporary file. - The file is created using Python's standard `tempfile.TemporaryFile` function in a - background thread, and is wrapped as an asynchronous file using `AsyncFile`. - - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file. Only applicable in - text mode. - :param newline: Controls how universal newlines mode works (only applicable in text - mode). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param errors: The error handling scheme used for encoding/decoding errors. - """ - - _async_file: AsyncFile[AnyStr] - - @overload - def __init__( - self: TemporaryFile[bytes], - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - @overload - def __init__( - self: TemporaryFile[str], - mode: OpenTextMode, - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - - def __init__( - self, - mode: OpenTextMode | OpenBinaryMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - *, - errors: str | None = None, - ) -> None: - self.mode = mode - self.buffering = buffering - self.encoding = encoding - self.newline = newline - self.suffix: str | None = suffix - self.prefix: str | None = prefix - self.dir: str | None = dir - self.errors = errors - - async def __aenter__(self) -> AsyncFile[AnyStr]: - fp = await to_thread.run_sync( - lambda: tempfile.TemporaryFile( - self.mode, - self.buffering, - self.encoding, - self.newline, - self.suffix, - self.prefix, - self.dir, - errors=self.errors, - ) - ) - self._async_file = AsyncFile(fp) - return self._async_file - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - await self._async_file.aclose() - - -class NamedTemporaryFile(Generic[AnyStr]): - """ - An asynchronous named temporary file that is automatically created and cleaned up. - - This class provides an asynchronous context manager for a temporary file with a - visible name in the file system. It uses Python's standard - :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with - :class:`AsyncFile` for asynchronous operations. - - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file. Only applicable in - text mode. - :param newline: Controls how universal newlines mode works (only applicable in text - mode). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param delete: Whether to delete the file when it is closed. - :param errors: The error handling scheme used for encoding/decoding errors. - :param delete_on_close: (Python 3.12+) Whether to delete the file on close. - """ - - _async_file: AsyncFile[AnyStr] - - @overload - def __init__( - self: NamedTemporaryFile[bytes], - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - delete: bool = ..., - *, - errors: str | None = ..., - delete_on_close: bool = ..., - ): ... - @overload - def __init__( - self: NamedTemporaryFile[str], - mode: OpenTextMode, - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - delete: bool = ..., - *, - errors: str | None = ..., - delete_on_close: bool = ..., - ): ... - - def __init__( - self, - mode: OpenBinaryMode | OpenTextMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - delete: bool = True, - *, - errors: str | None = None, - delete_on_close: bool = True, - ) -> None: - self._params: dict[str, Any] = { - "mode": mode, - "buffering": buffering, - "encoding": encoding, - "newline": newline, - "suffix": suffix, - "prefix": prefix, - "dir": dir, - "delete": delete, - "errors": errors, - } - if sys.version_info >= (3, 12): - self._params["delete_on_close"] = delete_on_close - - async def __aenter__(self) -> AsyncFile[AnyStr]: - fp = await to_thread.run_sync( - lambda: tempfile.NamedTemporaryFile(**self._params) - ) - self._async_file = AsyncFile(fp) - return self._async_file - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - await self._async_file.aclose() - - -class SpooledTemporaryFile(AsyncFile[AnyStr]): - """ - An asynchronous spooled temporary file that starts in memory and is spooled to disk. - - This class provides an asynchronous interface to a spooled temporary file, much like - Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous - write operations and provides a method to force a rollover to disk. - - :param max_size: Maximum size in bytes before the file is rolled over to disk. - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file (text mode only). - :param newline: Controls how universal newlines mode works (text mode only). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param errors: The error handling scheme used for encoding/decoding errors. - """ - - _rolled: bool = False - - @overload - def __init__( - self: SpooledTemporaryFile[bytes], - max_size: int = ..., - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - @overload - def __init__( - self: SpooledTemporaryFile[str], - max_size: int = ..., - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - - def __init__( - self, - max_size: int = 0, - mode: OpenBinaryMode | OpenTextMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - *, - errors: str | None = None, - ) -> None: - self._tempfile_params: dict[str, Any] = { - "mode": mode, - "buffering": buffering, - "encoding": encoding, - "newline": newline, - "suffix": suffix, - "prefix": prefix, - "dir": dir, - "errors": errors, - } - self._max_size = max_size - if "b" in mode: - super().__init__(BytesIO()) # type: ignore[arg-type] - else: - super().__init__( - TextIOWrapper( # type: ignore[arg-type] - BytesIO(), - encoding=encoding, - errors=errors, - newline=newline, - write_through=True, - ) - ) - - async def aclose(self) -> None: - if not self._rolled: - self._fp.close() - return - - await super().aclose() - - async def _check(self) -> None: - if self._rolled or self._fp.tell() <= self._max_size: - return - - await self.rollover() - - async def rollover(self) -> None: - if self._rolled: - return - - self._rolled = True - buffer = self._fp - buffer.seek(0) - self._fp = await to_thread.run_sync( - lambda: tempfile.TemporaryFile(**self._tempfile_params) - ) - await self.write(buffer.read()) - buffer.close() - - @property - def closed(self) -> bool: - return self._fp.closed - - async def read(self, size: int = -1) -> AnyStr: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.read(size) - - return await super().read(size) # type: ignore[return-value] - - async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.read1(size) - - return await super().read1(size) - - async def readline(self) -> AnyStr: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.readline() - - return await super().readline() # type: ignore[return-value] - - async def readlines(self) -> list[AnyStr]: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.readlines() - - return await super().readlines() # type: ignore[return-value] - - async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - self._fp.readinto(b) - - return await super().readinto(b) - - async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - self._fp.readinto(b) - - return await super().readinto1(b) - - async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.seek(offset, whence) - - return await super().seek(offset, whence) - - async def tell(self) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.tell() - - return await super().tell() - - async def truncate(self, size: int | None = None) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.truncate(size) - - return await super().truncate(size) - - @overload - async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ... - @overload - async def write(self: SpooledTemporaryFile[str], b: str) -> int: ... - - async def write(self, b: ReadableBuffer | str) -> int: - """ - Asynchronously write data to the spooled temporary file. - - If the file has not yet been rolled over, the data is written synchronously, - and a rollover is triggered if the size exceeds the maximum size. - - :param s: The data to write. - :return: The number of bytes written. - :raises RuntimeError: If the underlying file is not initialized. - - """ - if not self._rolled: - await checkpoint_if_cancelled() - result = self._fp.write(b) - await self._check() - return result - - return await super().write(b) # type: ignore[misc] - - @overload - async def writelines( - self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer] - ) -> None: ... - @overload - async def writelines( - self: SpooledTemporaryFile[str], lines: Iterable[str] - ) -> None: ... - - async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None: - """ - Asynchronously write a list of lines to the spooled temporary file. - - If the file has not yet been rolled over, the lines are written synchronously, - and a rollover is triggered if the size exceeds the maximum size. - - :param lines: An iterable of lines to write. - :raises RuntimeError: If the underlying file is not initialized. - - """ - if not self._rolled: - await checkpoint_if_cancelled() - result = self._fp.writelines(lines) - await self._check() - return result - - return await super().writelines(lines) # type: ignore[misc] - - -class TemporaryDirectory(Generic[AnyStr]): - """ - An asynchronous temporary directory that is created and cleaned up automatically. - - This class provides an asynchronous context manager for creating a temporary - directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to - perform directory creation and cleanup operations in a background thread. - - :param suffix: Suffix to be added to the temporary directory name. - :param prefix: Prefix to be added to the temporary directory name. - :param dir: The parent directory where the temporary directory is created. - :param ignore_cleanup_errors: Whether to ignore errors during cleanup - (Python 3.10+). - :param delete: Whether to delete the directory upon closing (Python 3.12+). - """ - - def __init__( - self, - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, - *, - ignore_cleanup_errors: bool = False, - delete: bool = True, - ) -> None: - self.suffix: AnyStr | None = suffix - self.prefix: AnyStr | None = prefix - self.dir: AnyStr | None = dir - self.ignore_cleanup_errors = ignore_cleanup_errors - self.delete = delete - - self._tempdir: tempfile.TemporaryDirectory | None = None - - async def __aenter__(self) -> str: - params: dict[str, Any] = { - "suffix": self.suffix, - "prefix": self.prefix, - "dir": self.dir, - } - if sys.version_info >= (3, 10): - params["ignore_cleanup_errors"] = self.ignore_cleanup_errors - - if sys.version_info >= (3, 12): - params["delete"] = self.delete - - self._tempdir = await to_thread.run_sync( - lambda: tempfile.TemporaryDirectory(**params) - ) - return await to_thread.run_sync(self._tempdir.__enter__) - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - if self._tempdir is not None: - await to_thread.run_sync( - self._tempdir.__exit__, exc_type, exc_value, traceback - ) - - async def cleanup(self) -> None: - if self._tempdir is not None: - await to_thread.run_sync(self._tempdir.cleanup) - - -@overload -async def mkstemp( - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - text: bool = False, -) -> tuple[int, str]: ... - - -@overload -async def mkstemp( - suffix: bytes | None = None, - prefix: bytes | None = None, - dir: bytes | None = None, - text: bool = False, -) -> tuple[int, bytes]: ... - - -async def mkstemp( - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, - text: bool = False, -) -> tuple[int, str | bytes]: - """ - Asynchronously create a temporary file and return an OS-level handle and the file - name. - - This function wraps `tempfile.mkstemp` and executes it in a background thread. - - :param suffix: Suffix to be added to the file name. - :param prefix: Prefix to be added to the file name. - :param dir: Directory in which the temporary file is created. - :param text: Whether the file is opened in text mode. - :return: A tuple containing the file descriptor and the file name. - - """ - return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text) - - -@overload -async def mkdtemp( - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, -) -> str: ... - - -@overload -async def mkdtemp( - suffix: bytes | None = None, - prefix: bytes | None = None, - dir: bytes | None = None, -) -> bytes: ... - - -async def mkdtemp( - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, -) -> str | bytes: - """ - Asynchronously create a temporary directory and return its path. - - This function wraps `tempfile.mkdtemp` and executes it in a background thread. - - :param suffix: Suffix to be added to the directory name. - :param prefix: Prefix to be added to the directory name. - :param dir: Parent directory where the temporary directory is created. - :return: The path of the created temporary directory. - - """ - return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir) - - -async def gettempdir() -> str: - """ - Asynchronously return the name of the directory used for temporary files. - - This function wraps `tempfile.gettempdir` and executes it in a background thread. - - :return: The path of the temporary directory as a string. - - """ - return await to_thread.run_sync(tempfile.gettempdir) - - -async def gettempdirb() -> bytes: - """ - Asynchronously return the name of the directory used for temporary files in bytes. - - This function wraps `tempfile.gettempdirb` and executes it in a background thread. - - :return: The path of the temporary directory as bytes. - - """ - return await to_thread.run_sync(tempfile.gettempdirb) diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_testing.py b/venv/lib/python3.10/site-packages/anyio/_core/_testing.py deleted file mode 100644 index 369e65c068a426e99b7e8571209e80ce35b71f47..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_testing.py +++ /dev/null @@ -1,82 +0,0 @@ -from __future__ import annotations - -from collections.abc import Awaitable, Generator -from typing import Any, cast - -from ._eventloop import get_async_backend - - -class TaskInfo: - """ - Represents an asynchronous task. - - :ivar int id: the unique identifier of the task - :ivar parent_id: the identifier of the parent task, if any - :vartype parent_id: Optional[int] - :ivar str name: the description of the task (if any) - :ivar ~collections.abc.Coroutine coro: the coroutine object of the task - """ - - __slots__ = "_name", "id", "parent_id", "name", "coro" - - def __init__( - self, - id: int, - parent_id: int | None, - name: str | None, - coro: Generator[Any, Any, Any] | Awaitable[Any], - ): - func = get_current_task - self._name = f"{func.__module__}.{func.__qualname__}" - self.id: int = id - self.parent_id: int | None = parent_id - self.name: str | None = name - self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro - - def __eq__(self, other: object) -> bool: - if isinstance(other, TaskInfo): - return self.id == other.id - - return NotImplemented - - def __hash__(self) -> int: - return hash(self.id) - - def __repr__(self) -> str: - return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})" - - def has_pending_cancellation(self) -> bool: - """ - Return ``True`` if the task has a cancellation pending, ``False`` otherwise. - - """ - return False - - -def get_current_task() -> TaskInfo: - """ - Return the current task. - - :return: a representation of the current task - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().get_current_task() - - -def get_running_tasks() -> list[TaskInfo]: - """ - Return a list of running tasks in the current event loop. - - :return: a list of task info objects - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return cast("list[TaskInfo]", get_async_backend().get_running_tasks()) - - -async def wait_all_tasks_blocked() -> None: - """Wait until all other tasks are waiting for something.""" - await get_async_backend().wait_all_tasks_blocked() diff --git a/venv/lib/python3.10/site-packages/anyio/_core/_typedattr.py b/venv/lib/python3.10/site-packages/anyio/_core/_typedattr.py deleted file mode 100644 index f358a448cb12739fd4eda4f4859d3a24ddd1de63..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/_core/_typedattr.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from collections.abc import Callable, Mapping -from typing import Any, TypeVar, final, overload - -from ._exceptions import TypedAttributeLookupError - -T_Attr = TypeVar("T_Attr") -T_Default = TypeVar("T_Default") -undefined = object() - - -def typed_attribute() -> Any: - """Return a unique object, used to mark typed attributes.""" - return object() - - -class TypedAttributeSet: - """ - Superclass for typed attribute collections. - - Checks that every public attribute of every subclass has a type annotation. - """ - - def __init_subclass__(cls) -> None: - annotations: dict[str, Any] = getattr(cls, "__annotations__", {}) - for attrname in dir(cls): - if not attrname.startswith("_") and attrname not in annotations: - raise TypeError( - f"Attribute {attrname!r} is missing its type annotation" - ) - - super().__init_subclass__() - - -class TypedAttributeProvider: - """Base class for classes that wish to provide typed extra attributes.""" - - @property - def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]: - """ - A mapping of the extra attributes to callables that return the corresponding - values. - - If the provider wraps another provider, the attributes from that wrapper should - also be included in the returned mapping (but the wrapper may override the - callables from the wrapped instance). - - """ - return {} - - @overload - def extra(self, attribute: T_Attr) -> T_Attr: ... - - @overload - def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ... - - @final - def extra(self, attribute: Any, default: object = undefined) -> object: - """ - extra(attribute, default=undefined) - - Return the value of the given typed extra attribute. - - :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to - look for - :param default: the value that should be returned if no value is found for the - attribute - :raises ~anyio.TypedAttributeLookupError: if the search failed and no default - value was given - - """ - try: - getter = self.extra_attributes[attribute] - except KeyError: - if default is undefined: - raise TypedAttributeLookupError("Attribute not found") from None - else: - return default - - return getter() diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__init__.py b/venv/lib/python3.10/site-packages/anyio/abc/__init__.py deleted file mode 100644 index d560ce3f1fa45a7ee4a3bc8958aa59702caa9d0c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/__init__.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -from ._eventloop import AsyncBackend as AsyncBackend -from ._resources import AsyncResource as AsyncResource -from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket -from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket -from ._sockets import IPAddressType as IPAddressType -from ._sockets import IPSockAddrType as IPSockAddrType -from ._sockets import SocketAttribute as SocketAttribute -from ._sockets import SocketListener as SocketListener -from ._sockets import SocketStream as SocketStream -from ._sockets import UDPPacketType as UDPPacketType -from ._sockets import UDPSocket as UDPSocket -from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType -from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket -from ._sockets import UNIXSocketStream as UNIXSocketStream -from ._streams import AnyByteReceiveStream as AnyByteReceiveStream -from ._streams import AnyByteSendStream as AnyByteSendStream -from ._streams import AnyByteStream as AnyByteStream -from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable -from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream -from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream -from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream -from ._streams import ByteReceiveStream as ByteReceiveStream -from ._streams import ByteSendStream as ByteSendStream -from ._streams import ByteStream as ByteStream -from ._streams import ByteStreamConnectable as ByteStreamConnectable -from ._streams import Listener as Listener -from ._streams import ObjectReceiveStream as ObjectReceiveStream -from ._streams import ObjectSendStream as ObjectSendStream -from ._streams import ObjectStream as ObjectStream -from ._streams import ObjectStreamConnectable as ObjectStreamConnectable -from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream -from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream -from ._streams import UnreliableObjectStream as UnreliableObjectStream -from ._subprocesses import Process as Process -from ._tasks import TaskGroup as TaskGroup -from ._tasks import TaskStatus as TaskStatus -from ._testing import TestRunner as TestRunner - -# Re-exported here, for backwards compatibility -# isort: off -from .._core._synchronization import ( - CapacityLimiter as CapacityLimiter, - Condition as Condition, - Event as Event, - Lock as Lock, - Semaphore as Semaphore, -) -from .._core._tasks import CancelScope as CancelScope -from ..from_thread import BlockingPortal as BlockingPortal - -# Re-export imports so they look like they live directly in this package -for __value in list(locals().values()): - if getattr(__value, "__module__", "").startswith("anyio.abc."): - __value.__module__ = __name__ - -del __value diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 5a7bddb8033414a1230fcf9eebfc6b79d65286c9..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_eventloop.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_eventloop.cpython-310.pyc deleted file mode 100644 index 204a219de7ca3404513ffe93e630171fdc60cfe6..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_eventloop.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_resources.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_resources.cpython-310.pyc deleted file mode 100644 index 44e1528d9d9112d61f6352516dd88217c2e5d008..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_resources.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_sockets.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_sockets.cpython-310.pyc deleted file mode 100644 index 82e2d05bbe4132b597779a65d730ad368d986bd2..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_sockets.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_streams.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_streams.cpython-310.pyc deleted file mode 100644 index ef4216764d3a7824920bbfa37548bb47a1333c2f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_streams.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-310.pyc deleted file mode 100644 index ba8b9282ab352f2001d4d50b729522d93097b3c7..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_tasks.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_tasks.cpython-310.pyc deleted file mode 100644 index f89e15d8dd18fb60fa0b1ac078ab5734c676c461..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_tasks.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_testing.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_testing.cpython-310.pyc deleted file mode 100644 index 134739699efaf3db5f1e53ac5f541fe248366971..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_testing.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/abc/_eventloop.py b/venv/lib/python3.10/site-packages/anyio/abc/_eventloop.py deleted file mode 100644 index b1bd085596d634939d9894c4725e5cb01726fcb3..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/_eventloop.py +++ /dev/null @@ -1,414 +0,0 @@ -from __future__ import annotations - -import math -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import AsyncIterator, Awaitable, Callable, Sequence -from contextlib import AbstractContextManager -from os import PathLike -from signal import Signals -from socket import AddressFamily, SocketKind, socket -from typing import ( - IO, - TYPE_CHECKING, - Any, - TypeVar, - Union, - overload, -) - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - - from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore - from .._core._tasks import CancelScope - from .._core._testing import TaskInfo - from ._sockets import ( - ConnectedUDPSocket, - ConnectedUNIXDatagramSocket, - IPSockAddrType, - SocketListener, - SocketStream, - UDPSocket, - UNIXDatagramSocket, - UNIXSocketStream, - ) - from ._subprocesses import Process - from ._tasks import TaskGroup - from ._testing import TestRunner - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") -StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"] - - -class AsyncBackend(metaclass=ABCMeta): - @classmethod - @abstractmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - """ - Run the given coroutine function in an asynchronous event loop. - - The current thread must not be already running an event loop. - - :param func: a coroutine function - :param args: positional arguments to ``func`` - :param kwargs: positional arguments to ``func`` - :param options: keyword arguments to call the backend ``run()`` implementation - with - :return: the return value of the coroutine function - """ - - @classmethod - @abstractmethod - def current_token(cls) -> object: - """ - Return an object that allows other threads to run code inside the event loop. - - :return: a token object, specific to the event loop running in the current - thread - """ - - @classmethod - @abstractmethod - def current_time(cls) -> float: - """ - Return the current value of the event loop's internal clock. - - :return: the clock value (seconds) - """ - - @classmethod - @abstractmethod - def cancelled_exception_class(cls) -> type[BaseException]: - """Return the exception class that is raised in a task if it's cancelled.""" - - @classmethod - @abstractmethod - async def checkpoint(cls) -> None: - """ - Check if the task has been cancelled, and allow rescheduling of other tasks. - - This is effectively the same as running :meth:`checkpoint_if_cancelled` and then - :meth:`cancel_shielded_checkpoint`. - """ - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - """ - Check if the current task group has been cancelled. - - This will check if the task has been cancelled, but will not allow other tasks - to be scheduled if not. - - """ - if cls.current_effective_deadline() == -math.inf: - await cls.checkpoint() - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - """ - Allow the rescheduling of other tasks. - - This will give other tasks the opportunity to run, but without checking if the - current task group has been cancelled, unlike with :meth:`checkpoint`. - - """ - with cls.create_cancel_scope(shield=True): - await cls.sleep(0) - - @classmethod - @abstractmethod - async def sleep(cls, delay: float) -> None: - """ - Pause the current task for the specified duration. - - :param delay: the duration, in seconds - """ - - @classmethod - @abstractmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - pass - - @classmethod - @abstractmethod - def current_effective_deadline(cls) -> float: - """ - Return the nearest deadline among all the cancel scopes effective for the - current task. - - :return: - - a clock value from the event loop's internal clock - - ``inf`` if there is no deadline in effect - - ``-inf`` if the current scope has been cancelled - :rtype: float - """ - - @classmethod - @abstractmethod - def create_task_group(cls) -> TaskGroup: - pass - - @classmethod - @abstractmethod - def create_event(cls) -> Event: - pass - - @classmethod - @abstractmethod - def create_lock(cls, *, fast_acquire: bool) -> Lock: - pass - - @classmethod - @abstractmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - pass - - @classmethod - @abstractmethod - def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: - pass - - @classmethod - @abstractmethod - async def run_sync_in_worker_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: CapacityLimiter | None = None, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - def check_cancelled(cls) -> None: - pass - - @classmethod - @abstractmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - pass - - @classmethod - @abstractmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None: - pass - - @classmethod - @abstractmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> SocketStream: - pass - - @classmethod - @abstractmethod - async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream: - pass - - @classmethod - @abstractmethod - def create_tcp_listener(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - def create_unix_listener(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - async def create_udp_socket( - cls, - family: AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - pass - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: None - ) -> UNIXDatagramSocket: ... - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: str | bytes - ) -> ConnectedUNIXDatagramSocket: ... - - @classmethod - @abstractmethod - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: str | bytes | None - ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - pass - - @classmethod - @abstractmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - pass - - @classmethod - @abstractmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - async def wrap_listener_socket(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - async def wrap_stream_socket(cls, sock: socket) -> SocketStream: - pass - - @classmethod - @abstractmethod - async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream: - pass - - @classmethod - @abstractmethod - async def wrap_udp_socket(cls, sock: socket) -> UDPSocket: - pass - - @classmethod - @abstractmethod - async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket: - pass - - @classmethod - @abstractmethod - async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket - ) -> ConnectedUNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - pass - - @classmethod - @abstractmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - pass - - @classmethod - @abstractmethod - def get_current_task(cls) -> TaskInfo: - pass - - @classmethod - @abstractmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - pass - - @classmethod - @abstractmethod - async def wait_all_tasks_blocked(cls) -> None: - pass - - @classmethod - @abstractmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - pass diff --git a/venv/lib/python3.10/site-packages/anyio/abc/_resources.py b/venv/lib/python3.10/site-packages/anyio/abc/_resources.py deleted file mode 100644 index 10df115a7b9f975493476da763cc1e26dbd822e5..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/_resources.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations - -from abc import ABCMeta, abstractmethod -from types import TracebackType -from typing import TypeVar - -T = TypeVar("T") - - -class AsyncResource(metaclass=ABCMeta): - """ - Abstract base class for all closeable asynchronous resources. - - Works as an asynchronous context manager which returns the instance itself on enter, - and calls :meth:`aclose` on exit. - """ - - __slots__ = () - - async def __aenter__(self: T) -> T: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.aclose() - - @abstractmethod - async def aclose(self) -> None: - """Close the resource.""" diff --git a/venv/lib/python3.10/site-packages/anyio/abc/_sockets.py b/venv/lib/python3.10/site-packages/anyio/abc/_sockets.py deleted file mode 100644 index 3ff60d4d9dfc3c15d416c9fc4a6b3b7f79a9fdb1..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/_sockets.py +++ /dev/null @@ -1,405 +0,0 @@ -from __future__ import annotations - -import errno -import socket -import sys -from abc import abstractmethod -from collections.abc import Callable, Collection, Mapping -from contextlib import AsyncExitStack -from io import IOBase -from ipaddress import IPv4Address, IPv6Address -from socket import AddressFamily -from typing import Any, TypeVar, Union - -from .._core._eventloop import get_async_backend -from .._core._typedattr import ( - TypedAttributeProvider, - TypedAttributeSet, - typed_attribute, -) -from ._streams import ByteStream, Listener, UnreliableObjectStream -from ._tasks import TaskGroup - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -IPAddressType: TypeAlias = Union[str, IPv4Address, IPv6Address] -IPSockAddrType: TypeAlias = tuple[str, int] -SockAddrType: TypeAlias = Union[IPSockAddrType, str] -UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType] -UNIXDatagramPacketType: TypeAlias = tuple[bytes, str] -T_Retval = TypeVar("T_Retval") - - -def _validate_socket( - sock_or_fd: socket.socket | int, - sock_type: socket.SocketKind, - addr_family: socket.AddressFamily = socket.AF_UNSPEC, - *, - require_connected: bool = False, - require_bound: bool = False, -) -> socket.socket: - if isinstance(sock_or_fd, int): - try: - sock = socket.socket(fileno=sock_or_fd) - except OSError as exc: - if exc.errno == errno.ENOTSOCK: - raise ValueError( - "the file descriptor does not refer to a socket" - ) from exc - elif require_connected: - raise ValueError("the socket must be connected") from exc - elif require_bound: - raise ValueError("the socket must be bound to a local address") from exc - else: - raise - elif isinstance(sock_or_fd, socket.socket): - sock = sock_or_fd - else: - raise TypeError( - f"expected an int or socket, got {type(sock_or_fd).__qualname__} instead" - ) - - try: - if require_connected: - try: - sock.getpeername() - except OSError as exc: - raise ValueError("the socket must be connected") from exc - - if require_bound: - try: - if sock.family in (socket.AF_INET, socket.AF_INET6): - bound_addr = sock.getsockname()[1] - else: - bound_addr = sock.getsockname() - except OSError: - bound_addr = None - - if not bound_addr: - raise ValueError("the socket must be bound to a local address") - - if addr_family != socket.AF_UNSPEC and sock.family != addr_family: - raise ValueError( - f"address family mismatch: expected {addr_family.name}, got " - f"{sock.family.name}" - ) - - if sock.type != sock_type: - raise ValueError( - f"socket type mismatch: expected {sock_type.name}, got {sock.type.name}" - ) - except BaseException: - # Avoid ResourceWarning from the locally constructed socket object - if isinstance(sock_or_fd, int): - sock.detach() - - raise - - sock.setblocking(False) - return sock - - -class SocketAttribute(TypedAttributeSet): - """ - .. attribute:: family - :type: socket.AddressFamily - - the address family of the underlying socket - - .. attribute:: local_address - :type: tuple[str, int] | str - - the local address the underlying socket is connected to - - .. attribute:: local_port - :type: int - - for IP based sockets, the local port the underlying socket is bound to - - .. attribute:: raw_socket - :type: socket.socket - - the underlying stdlib socket object - - .. attribute:: remote_address - :type: tuple[str, int] | str - - the remote address the underlying socket is connected to - - .. attribute:: remote_port - :type: int - - for IP based sockets, the remote port the underlying socket is connected to - """ - - family: AddressFamily = typed_attribute() - local_address: SockAddrType = typed_attribute() - local_port: int = typed_attribute() - raw_socket: socket.socket = typed_attribute() - remote_address: SockAddrType = typed_attribute() - remote_port: int = typed_attribute() - - -class _SocketProvider(TypedAttributeProvider): - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - from .._core._sockets import convert_ipv6_sockaddr as convert - - attributes: dict[Any, Callable[[], Any]] = { - SocketAttribute.family: lambda: self._raw_socket.family, - SocketAttribute.local_address: lambda: convert( - self._raw_socket.getsockname() - ), - SocketAttribute.raw_socket: lambda: self._raw_socket, - } - try: - peername: tuple[str, int] | None = convert(self._raw_socket.getpeername()) - except OSError: - peername = None - - # Provide the remote address for connected sockets - if peername is not None: - attributes[SocketAttribute.remote_address] = lambda: peername - - # Provide local and remote ports for IP based sockets - if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6): - attributes[SocketAttribute.local_port] = ( - lambda: self._raw_socket.getsockname()[1] - ) - if peername is not None: - remote_port = peername[1] - attributes[SocketAttribute.remote_port] = lambda: remote_port - - return attributes - - @property - @abstractmethod - def _raw_socket(self) -> socket.socket: - pass - - -class SocketStream(ByteStream, _SocketProvider): - """ - Transports bytes over a socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> SocketStream: - """ - Wrap an existing socket object or file descriptor as a socket stream. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a socket stream - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_connected=True) - return await get_async_backend().wrap_stream_socket(sock) - - -class UNIXSocketStream(SocketStream): - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> UNIXSocketStream: - """ - Wrap an existing socket object or file descriptor as a UNIX socket stream. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a UNIX socket stream - - """ - sock = _validate_socket( - sock_or_fd, socket.SOCK_STREAM, socket.AF_UNIX, require_connected=True - ) - return await get_async_backend().wrap_unix_stream_socket(sock) - - @abstractmethod - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - """ - Send file descriptors along with a message to the peer. - - :param message: a non-empty bytestring - :param fds: a collection of files (either numeric file descriptors or open file - or socket objects) - """ - - @abstractmethod - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - """ - Receive file descriptors along with a message from the peer. - - :param msglen: length of the message to expect from the peer - :param maxfds: maximum number of file descriptors to expect from the peer - :return: a tuple of (message, file descriptors) - """ - - -class SocketListener(Listener[SocketStream], _SocketProvider): - """ - Listens to incoming socket connections. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> SocketListener: - """ - Wrap an existing socket object or file descriptor as a socket listener. - - The newly created listener takes ownership of the socket being passed in. - - :param sock_or_fd: a socket object or file descriptor - :return: a socket listener - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_bound=True) - return await get_async_backend().wrap_listener_socket(sock) - - @abstractmethod - async def accept(self) -> SocketStream: - """Accept an incoming connection.""" - - async def serve( - self, - handler: Callable[[SocketStream], Any], - task_group: TaskGroup | None = None, - ) -> None: - from .. import create_task_group - - async with AsyncExitStack() as stack: - if task_group is None: - task_group = await stack.enter_async_context(create_task_group()) - - while True: - stream = await self.accept() - task_group.start_soon(handler, stream) - - -class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider): - """ - Represents an unconnected UDP socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> UDPSocket: - """ - Wrap an existing socket object or file descriptor as a UDP socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must be bound to a local address. - - :param sock_or_fd: a socket object or file descriptor - :return: a UDP socket - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, require_bound=True) - return await get_async_backend().wrap_udp_socket(sock) - - async def sendto(self, data: bytes, host: str, port: int) -> None: - """ - Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))). - - """ - return await self.send((data, (host, port))) - - -class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider): - """ - Represents an connected UDP socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> ConnectedUDPSocket: - """ - Wrap an existing socket object or file descriptor as a connected UDP socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a connected UDP socket - - """ - sock = _validate_socket( - sock_or_fd, - socket.SOCK_DGRAM, - require_connected=True, - ) - return await get_async_backend().wrap_connected_udp_socket(sock) - - -class UNIXDatagramSocket( - UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider -): - """ - Represents an unconnected Unix datagram socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> UNIXDatagramSocket: - """ - Wrap an existing socket object or file descriptor as a UNIX datagram - socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - - :param sock_or_fd: a socket object or file descriptor - :return: a UNIX datagram socket - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX) - return await get_async_backend().wrap_unix_datagram_socket(sock) - - async def sendto(self, data: bytes, path: str) -> None: - """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path)).""" - return await self.send((data, path)) - - -class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider): - """ - Represents a connected Unix datagram socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> ConnectedUNIXDatagramSocket: - """ - Wrap an existing socket object or file descriptor as a connected UNIX datagram - socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a connected UNIX datagram socket - - """ - sock = _validate_socket( - sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX, require_connected=True - ) - return await get_async_backend().wrap_connected_unix_datagram_socket(sock) diff --git a/venv/lib/python3.10/site-packages/anyio/abc/_streams.py b/venv/lib/python3.10/site-packages/anyio/abc/_streams.py deleted file mode 100644 index 369df3f36cda74aa0d0893cd98bd4b29d3786faa..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/_streams.py +++ /dev/null @@ -1,239 +0,0 @@ -from __future__ import annotations - -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import Callable -from typing import Any, Generic, TypeVar, Union - -from .._core._exceptions import EndOfStream -from .._core._typedattr import TypedAttributeProvider -from ._resources import AsyncResource -from ._tasks import TaskGroup - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -T_Item = TypeVar("T_Item") -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True) - - -class UnreliableObjectReceiveStream( - Generic[T_co], AsyncResource, TypedAttributeProvider -): - """ - An interface for receiving objects. - - This interface makes no guarantees that the received messages arrive in the order in - which they were sent, or that no messages are missed. - - Asynchronously iterating over objects of this type will yield objects matching the - given type parameter. - """ - - def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]: - return self - - async def __anext__(self) -> T_co: - try: - return await self.receive() - except EndOfStream: - raise StopAsyncIteration from None - - @abstractmethod - async def receive(self) -> T_co: - """ - Receive the next item. - - :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly - closed - :raises ~anyio.EndOfStream: if this stream has been closed from the other end - :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable - due to external causes - """ - - -class UnreliableObjectSendStream( - Generic[T_contra], AsyncResource, TypedAttributeProvider -): - """ - An interface for sending objects. - - This interface makes no guarantees that the messages sent will reach the - recipient(s) in the same order in which they were sent, or at all. - """ - - @abstractmethod - async def send(self, item: T_contra) -> None: - """ - Send an item to the peer(s). - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if the send stream has been explicitly - closed - :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable - due to external causes - """ - - -class UnreliableObjectStream( - UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item] -): - """ - A bidirectional message stream which does not guarantee the order or reliability of - message delivery. - """ - - -class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]): - """ - A receive message stream which guarantees that messages are received in the same - order in which they were sent, and that no messages are missed. - """ - - -class ObjectSendStream(UnreliableObjectSendStream[T_contra]): - """ - A send message stream which guarantees that messages are delivered in the same order - in which they were sent, without missing any messages in the middle. - """ - - -class ObjectStream( - ObjectReceiveStream[T_Item], - ObjectSendStream[T_Item], - UnreliableObjectStream[T_Item], -): - """ - A bidirectional message stream which guarantees the order and reliability of message - delivery. - """ - - @abstractmethod - async def send_eof(self) -> None: - """ - Send an end-of-file indication to the peer. - - You should not try to send any further data to this stream after calling this - method. This method is idempotent (does nothing on successive calls). - """ - - -class ByteReceiveStream(AsyncResource, TypedAttributeProvider): - """ - An interface for receiving bytes from a single peer. - - Iterating this byte stream will yield a byte string of arbitrary length, but no more - than 65536 bytes. - """ - - def __aiter__(self) -> ByteReceiveStream: - return self - - async def __anext__(self) -> bytes: - try: - return await self.receive() - except EndOfStream: - raise StopAsyncIteration from None - - @abstractmethod - async def receive(self, max_bytes: int = 65536) -> bytes: - """ - Receive at most ``max_bytes`` bytes from the peer. - - .. note:: Implementers of this interface should not return an empty - :class:`bytes` object, and users should ignore them. - - :param max_bytes: maximum number of bytes to receive - :return: the received bytes - :raises ~anyio.EndOfStream: if this stream has been closed from the other end - """ - - -class ByteSendStream(AsyncResource, TypedAttributeProvider): - """An interface for sending bytes to a single peer.""" - - @abstractmethod - async def send(self, item: bytes) -> None: - """ - Send the given bytes to the peer. - - :param item: the bytes to send - """ - - -class ByteStream(ByteReceiveStream, ByteSendStream): - """A bidirectional byte stream.""" - - @abstractmethod - async def send_eof(self) -> None: - """ - Send an end-of-file indication to the peer. - - You should not try to send any further data to this stream after calling this - method. This method is idempotent (does nothing on successive calls). - """ - - -#: Type alias for all unreliable bytes-oriented receive streams. -AnyUnreliableByteReceiveStream: TypeAlias = Union[ - UnreliableObjectReceiveStream[bytes], ByteReceiveStream -] -#: Type alias for all unreliable bytes-oriented send streams. -AnyUnreliableByteSendStream: TypeAlias = Union[ - UnreliableObjectSendStream[bytes], ByteSendStream -] -#: Type alias for all unreliable bytes-oriented streams. -AnyUnreliableByteStream: TypeAlias = Union[UnreliableObjectStream[bytes], ByteStream] -#: Type alias for all bytes-oriented receive streams. -AnyByteReceiveStream: TypeAlias = Union[ObjectReceiveStream[bytes], ByteReceiveStream] -#: Type alias for all bytes-oriented send streams. -AnyByteSendStream: TypeAlias = Union[ObjectSendStream[bytes], ByteSendStream] -#: Type alias for all bytes-oriented streams. -AnyByteStream: TypeAlias = Union[ObjectStream[bytes], ByteStream] - - -class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider): - """An interface for objects that let you accept incoming connections.""" - - @abstractmethod - async def serve( - self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None - ) -> None: - """ - Accept incoming connections as they come in and start tasks to handle them. - - :param handler: a callable that will be used to handle each accepted connection - :param task_group: the task group that will be used to start tasks for handling - each accepted connection (if omitted, an ad-hoc task group will be created) - """ - - -class ObjectStreamConnectable(Generic[T_co], metaclass=ABCMeta): - @abstractmethod - async def connect(self) -> ObjectStream[T_co]: - """ - Connect to the remote endpoint. - - :return: an object stream connected to the remote end - :raises ConnectionFailed: if the connection fails - """ - - -class ByteStreamConnectable(metaclass=ABCMeta): - @abstractmethod - async def connect(self) -> ByteStream: - """ - Connect to the remote endpoint. - - :return: a bytestream connected to the remote end - :raises ConnectionFailed: if the connection fails - """ - - -#: Type alias for all connectables returning bytestreams or bytes-oriented object streams -AnyByteStreamConnectable: TypeAlias = Union[ - ObjectStreamConnectable[bytes], ByteStreamConnectable -] diff --git a/venv/lib/python3.10/site-packages/anyio/abc/_subprocesses.py b/venv/lib/python3.10/site-packages/anyio/abc/_subprocesses.py deleted file mode 100644 index ce0564ceac8aac425675b5c8f7f7205d08061fd3..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/_subprocesses.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from signal import Signals - -from ._resources import AsyncResource -from ._streams import ByteReceiveStream, ByteSendStream - - -class Process(AsyncResource): - """An asynchronous version of :class:`subprocess.Popen`.""" - - @abstractmethod - async def wait(self) -> int: - """ - Wait until the process exits. - - :return: the exit code of the process - """ - - @abstractmethod - def terminate(self) -> None: - """ - Terminates the process, gracefully if possible. - - On Windows, this calls ``TerminateProcess()``. - On POSIX systems, this sends ``SIGTERM`` to the process. - - .. seealso:: :meth:`subprocess.Popen.terminate` - """ - - @abstractmethod - def kill(self) -> None: - """ - Kills the process. - - On Windows, this calls ``TerminateProcess()``. - On POSIX systems, this sends ``SIGKILL`` to the process. - - .. seealso:: :meth:`subprocess.Popen.kill` - """ - - @abstractmethod - def send_signal(self, signal: Signals) -> None: - """ - Send a signal to the subprocess. - - .. seealso:: :meth:`subprocess.Popen.send_signal` - - :param signal: the signal number (e.g. :data:`signal.SIGHUP`) - """ - - @property - @abstractmethod - def pid(self) -> int: - """The process ID of the process.""" - - @property - @abstractmethod - def returncode(self) -> int | None: - """ - The return code of the process. If the process has not yet terminated, this will - be ``None``. - """ - - @property - @abstractmethod - def stdin(self) -> ByteSendStream | None: - """The stream for the standard input of the process.""" - - @property - @abstractmethod - def stdout(self) -> ByteReceiveStream | None: - """The stream for the standard output of the process.""" - - @property - @abstractmethod - def stderr(self) -> ByteReceiveStream | None: - """The stream for the standard error output of the process.""" diff --git a/venv/lib/python3.10/site-packages/anyio/abc/_tasks.py b/venv/lib/python3.10/site-packages/anyio/abc/_tasks.py deleted file mode 100644 index 516b3ec3b38a4b140f5d607dd28da989f057b832..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/_tasks.py +++ /dev/null @@ -1,117 +0,0 @@ -from __future__ import annotations - -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import Awaitable, Callable -from types import TracebackType -from typing import TYPE_CHECKING, Any, Protocol, overload - -if sys.version_info >= (3, 13): - from typing import TypeVar -else: - from typing_extensions import TypeVar - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if TYPE_CHECKING: - from .._core._tasks import CancelScope - -T_Retval = TypeVar("T_Retval") -T_contra = TypeVar("T_contra", contravariant=True, default=None) -PosArgsT = TypeVarTuple("PosArgsT") - - -class TaskStatus(Protocol[T_contra]): - @overload - def started(self: TaskStatus[None]) -> None: ... - - @overload - def started(self, value: T_contra) -> None: ... - - def started(self, value: T_contra | None = None) -> None: - """ - Signal that the task has started. - - :param value: object passed back to the starter of the task - """ - - -class TaskGroup(metaclass=ABCMeta): - """ - Groups several asynchronous tasks together. - - :ivar cancel_scope: the cancel scope inherited by all child tasks - :vartype cancel_scope: CancelScope - - .. note:: On asyncio, support for eager task factories is considered to be - **experimental**. In particular, they don't follow the usual semantics of new - tasks being scheduled on the next iteration of the event loop, and may thus - cause unexpected behavior in code that wasn't written with such semantics in - mind. - """ - - cancel_scope: CancelScope - - @abstractmethod - def start_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> None: - """ - Start a new task in this task group. - - :param func: a coroutine function - :param args: positional arguments to call the function with - :param name: name of the task, for the purposes of introspection and debugging - - .. versionadded:: 3.0 - """ - - @abstractmethod - async def start( - self, - func: Callable[..., Awaitable[Any]], - *args: object, - name: object = None, - ) -> Any: - """ - Start a new task and wait until it signals for readiness. - - The target callable must accept a keyword argument ``task_status`` (of type - :class:`TaskStatus`). Awaiting on this method will return whatever was passed to - ``task_status.started()`` (``None`` by default). - - .. note:: The :class:`TaskStatus` class is generic, and the type argument should - indicate the type of the value that will be passed to - ``task_status.started()``. - - :param func: a coroutine function that accepts the ``task_status`` keyword - argument - :param args: positional arguments to call the function with - :param name: an optional name for the task, for introspection and debugging - :return: the value passed to ``task_status.started()`` - :raises RuntimeError: if the task finishes without calling - ``task_status.started()`` - - .. seealso:: :ref:`start_initialize` - - .. versionadded:: 3.0 - """ - - @abstractmethod - async def __aenter__(self) -> TaskGroup: - """Enter the task group context and allow starting new tasks.""" - - @abstractmethod - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - """Exit the task group context waiting for all tasks to finish.""" diff --git a/venv/lib/python3.10/site-packages/anyio/abc/_testing.py b/venv/lib/python3.10/site-packages/anyio/abc/_testing.py deleted file mode 100644 index 7c50ed76dc4d8df41262973a0122295523e2a935..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/abc/_testing.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import annotations - -import types -from abc import ABCMeta, abstractmethod -from collections.abc import AsyncGenerator, Callable, Coroutine, Iterable -from typing import Any, TypeVar - -_T = TypeVar("_T") - - -class TestRunner(metaclass=ABCMeta): - """ - Encapsulates a running event loop. Every call made through this object will use the - same event loop. - """ - - def __enter__(self) -> TestRunner: - return self - - @abstractmethod - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: types.TracebackType | None, - ) -> bool | None: ... - - @abstractmethod - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[_T, Any]], - kwargs: dict[str, Any], - ) -> Iterable[_T]: - """ - Run an async generator fixture. - - :param fixture_func: the fixture function - :param kwargs: keyword arguments to call the fixture function with - :return: an iterator yielding the value yielded from the async generator - """ - - @abstractmethod - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, _T]], - kwargs: dict[str, Any], - ) -> _T: - """ - Run an async fixture. - - :param fixture_func: the fixture function - :param kwargs: keyword arguments to call the fixture function with - :return: the return value of the fixture function - """ - - @abstractmethod - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - """ - Run an async test function. - - :param test_func: the test function - :param kwargs: keyword arguments to call the test function with - """ diff --git a/venv/lib/python3.10/site-packages/anyio/from_thread.py b/venv/lib/python3.10/site-packages/anyio/from_thread.py deleted file mode 100644 index 837de5e96715b6ba324d156e9f4a2432a7ccf27d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/from_thread.py +++ /dev/null @@ -1,578 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "BlockingPortal", - "BlockingPortalProvider", - "check_cancelled", - "run", - "run_sync", - "start_blocking_portal", -) - -import sys -from collections.abc import Awaitable, Callable, Generator -from concurrent.futures import Future -from contextlib import ( - AbstractAsyncContextManager, - AbstractContextManager, - contextmanager, -) -from dataclasses import dataclass, field -from functools import partial -from inspect import isawaitable -from threading import Lock, Thread, current_thread, get_ident -from types import TracebackType -from typing import ( - Any, - Generic, - TypeVar, - cast, - overload, -) - -from ._core._eventloop import ( - get_cancelled_exc_class, - threadlocals, -) -from ._core._eventloop import run as run_eventloop -from ._core._exceptions import NoEventLoopError -from ._core._synchronization import Event -from ._core._tasks import CancelScope, create_task_group -from .abc._tasks import TaskStatus -from .lowlevel import EventLoopToken, current_token - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -T_Retval = TypeVar("T_Retval") -T_co = TypeVar("T_co", covariant=True) -PosArgsT = TypeVarTuple("PosArgsT") - - -def _token_or_error(token: EventLoopToken | None) -> EventLoopToken: - if token is not None: - return token - - try: - return threadlocals.current_token - except AttributeError: - raise NoEventLoopError( - "Not running inside an AnyIO worker thread, and no event loop token was " - "provided" - ) from None - - -def run( - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - token: EventLoopToken | None = None, -) -> T_Retval: - """ - Call a coroutine function from a worker thread. - - :param func: a coroutine function - :param args: positional arguments for the callable - :param token: an event loop token to use to get back to the event loop thread - (required if calling this function from outside an AnyIO worker thread) - :return: the return value of the coroutine function - :raises MissingTokenError: if no token was provided and called from outside an - AnyIO worker thread - :raises RunFinishedError: if the event loop tied to ``token`` is no longer running - - .. versionchanged:: 4.11.0 - Added the ``token`` parameter. - - """ - explicit_token = token is not None - token = _token_or_error(token) - return token.backend_class.run_async_from_thread( - func, args, token=token.native_token if explicit_token else None - ) - - -def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - token: EventLoopToken | None = None, -) -> T_Retval: - """ - Call a function in the event loop thread from a worker thread. - - :param func: a callable - :param args: positional arguments for the callable - :param token: an event loop token to use to get back to the event loop thread - (required if calling this function from outside an AnyIO worker thread) - :return: the return value of the callable - :raises MissingTokenError: if no token was provided and called from outside an - AnyIO worker thread - :raises RunFinishedError: if the event loop tied to ``token`` is no longer running - - .. versionchanged:: 4.11.0 - Added the ``token`` parameter. - - """ - explicit_token = token is not None - token = _token_or_error(token) - return token.backend_class.run_sync_from_thread( - func, args, token=token.native_token if explicit_token else None - ) - - -class _BlockingAsyncContextManager(Generic[T_co], AbstractContextManager): - _enter_future: Future[T_co] - _exit_future: Future[bool | None] - _exit_event: Event - _exit_exc_info: tuple[ - type[BaseException] | None, BaseException | None, TracebackType | None - ] = (None, None, None) - - def __init__( - self, async_cm: AbstractAsyncContextManager[T_co], portal: BlockingPortal - ): - self._async_cm = async_cm - self._portal = portal - - async def run_async_cm(self) -> bool | None: - try: - self._exit_event = Event() - value = await self._async_cm.__aenter__() - except BaseException as exc: - self._enter_future.set_exception(exc) - raise - else: - self._enter_future.set_result(value) - - try: - # Wait for the sync context manager to exit. - # This next statement can raise `get_cancelled_exc_class()` if - # something went wrong in a task group in this async context - # manager. - await self._exit_event.wait() - finally: - # In case of cancellation, it could be that we end up here before - # `_BlockingAsyncContextManager.__exit__` is called, and an - # `_exit_exc_info` has been set. - result = await self._async_cm.__aexit__(*self._exit_exc_info) - - return result - - def __enter__(self) -> T_co: - self._enter_future = Future() - self._exit_future = self._portal.start_task_soon(self.run_async_cm) - return self._enter_future.result() - - def __exit__( - self, - __exc_type: type[BaseException] | None, - __exc_value: BaseException | None, - __traceback: TracebackType | None, - ) -> bool | None: - self._exit_exc_info = __exc_type, __exc_value, __traceback - self._portal.call(self._exit_event.set) - return self._exit_future.result() - - -class _BlockingPortalTaskStatus(TaskStatus): - def __init__(self, future: Future): - self._future = future - - def started(self, value: object = None) -> None: - self._future.set_result(value) - - -class BlockingPortal: - """ - An object that lets external threads run code in an asynchronous event loop. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - """ - - def __init__(self) -> None: - self._token = current_token() - self._event_loop_thread_id: int | None = get_ident() - self._stop_event = Event() - self._task_group = create_task_group() - - async def __aenter__(self) -> BlockingPortal: - await self._task_group.__aenter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - await self.stop() - return await self._task_group.__aexit__(exc_type, exc_val, exc_tb) - - def _check_running(self) -> None: - if self._event_loop_thread_id is None: - raise RuntimeError("This portal is not running") - if self._event_loop_thread_id == get_ident(): - raise RuntimeError( - "This method cannot be called from the event loop thread" - ) - - async def sleep_until_stopped(self) -> None: - """Sleep until :meth:`stop` is called.""" - await self._stop_event.wait() - - async def stop(self, cancel_remaining: bool = False) -> None: - """ - Signal the portal to shut down. - - This marks the portal as no longer accepting new calls and exits from - :meth:`sleep_until_stopped`. - - :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False`` - to let them finish before returning - - """ - self._event_loop_thread_id = None - self._stop_event.set() - if cancel_remaining: - self._task_group.cancel_scope.cancel("the blocking portal is shutting down") - - async def _call_func( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - future: Future[T_Retval], - ) -> None: - def callback(f: Future[T_Retval]) -> None: - if f.cancelled(): - if self._event_loop_thread_id == get_ident(): - scope.cancel("the future was cancelled") - elif self._event_loop_thread_id is not None: - self.call(scope.cancel, "the future was cancelled") - - try: - retval_or_awaitable = func(*args, **kwargs) - if isawaitable(retval_or_awaitable): - with CancelScope() as scope: - future.add_done_callback(callback) - retval = await retval_or_awaitable - else: - retval = retval_or_awaitable - except get_cancelled_exc_class(): - future.cancel() - future.set_running_or_notify_cancel() - except BaseException as exc: - if not future.cancelled(): - future.set_exception(exc) - - # Let base exceptions fall through - if not isinstance(exc, Exception): - raise - else: - if not future.cancelled(): - future.set_result(retval) - finally: - scope = None # type: ignore[assignment] - - def _spawn_task_from_thread( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - name: object, - future: Future[T_Retval], - ) -> None: - """ - Spawn a new task using the given callable. - - :param func: a callable - :param args: positional arguments to be passed to the callable - :param kwargs: keyword arguments to be passed to the callable - :param name: name of the task (will be coerced to a string if not ``None``) - :param future: a future that will resolve to the return value of the callable, - or the exception raised during its execution - - """ - run_sync( - partial(self._task_group.start_soon, name=name), - self._call_func, - func, - args, - kwargs, - future, - token=self._token, - ) - - @overload - def call( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - ) -> T_Retval: ... - - @overload - def call( - self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] - ) -> T_Retval: ... - - def call( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - *args: Unpack[PosArgsT], - ) -> T_Retval: - """ - Call the given function in the event loop thread. - - If the callable returns a coroutine object, it is awaited on. - - :param func: any callable - :raises RuntimeError: if the portal is not running or if this method is called - from within the event loop thread - - """ - return cast(T_Retval, self.start_task_soon(func, *args).result()) - - @overload - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: ... - - @overload - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: ... - - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: - """ - Start a task in the portal's task group. - - The task will be run inside a cancel scope which can be cancelled by cancelling - the returned future. - - :param func: the target function - :param args: positional arguments passed to ``func`` - :param name: name of the task (will be coerced to a string if not ``None``) - :return: a future that resolves with the return value of the callable if the - task completes successfully, or with the exception raised in the task - :raises RuntimeError: if the portal is not running or if this method is called - from within the event loop thread - :rtype: concurrent.futures.Future[T_Retval] - - .. versionadded:: 3.0 - - """ - self._check_running() - f: Future[T_Retval] = Future() - self._spawn_task_from_thread(func, args, {}, name, f) - return f - - def start_task( - self, - func: Callable[..., Awaitable[T_Retval]], - *args: object, - name: object = None, - ) -> tuple[Future[T_Retval], Any]: - """ - Start a task in the portal's task group and wait until it signals for readiness. - - This method works the same way as :meth:`.abc.TaskGroup.start`. - - :param func: the target function - :param args: positional arguments passed to ``func`` - :param name: name of the task (will be coerced to a string if not ``None``) - :return: a tuple of (future, task_status_value) where the ``task_status_value`` - is the value passed to ``task_status.started()`` from within the target - function - :rtype: tuple[concurrent.futures.Future[T_Retval], Any] - - .. versionadded:: 3.0 - - """ - - def task_done(future: Future[T_Retval]) -> None: - if not task_status_future.done(): - if future.cancelled(): - task_status_future.cancel() - elif future.exception(): - task_status_future.set_exception(future.exception()) - else: - exc = RuntimeError( - "Task exited without calling task_status.started()" - ) - task_status_future.set_exception(exc) - - self._check_running() - task_status_future: Future = Future() - task_status = _BlockingPortalTaskStatus(task_status_future) - f: Future = Future() - f.add_done_callback(task_done) - self._spawn_task_from_thread(func, args, {"task_status": task_status}, name, f) - return f, task_status_future.result() - - def wrap_async_context_manager( - self, cm: AbstractAsyncContextManager[T_co] - ) -> AbstractContextManager[T_co]: - """ - Wrap an async context manager as a synchronous context manager via this portal. - - Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping - in the middle until the synchronous context manager exits. - - :param cm: an asynchronous context manager - :return: a synchronous context manager - - .. versionadded:: 2.1 - - """ - return _BlockingAsyncContextManager(cm, self) - - -@dataclass -class BlockingPortalProvider: - """ - A manager for a blocking portal. Used as a context manager. The first thread to - enter this context manager causes a blocking portal to be started with the specific - parameters, and the last thread to exit causes the portal to be shut down. Thus, - there will be exactly one blocking portal running in this context as long as at - least one thread has entered this context manager. - - The parameters are the same as for :func:`~anyio.run`. - - :param backend: name of the backend - :param backend_options: backend options - - .. versionadded:: 4.4 - """ - - backend: str = "asyncio" - backend_options: dict[str, Any] | None = None - _lock: Lock = field(init=False, default_factory=Lock) - _leases: int = field(init=False, default=0) - _portal: BlockingPortal = field(init=False) - _portal_cm: AbstractContextManager[BlockingPortal] | None = field( - init=False, default=None - ) - - def __enter__(self) -> BlockingPortal: - with self._lock: - if self._portal_cm is None: - self._portal_cm = start_blocking_portal( - self.backend, self.backend_options - ) - self._portal = self._portal_cm.__enter__() - - self._leases += 1 - return self._portal - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - portal_cm: AbstractContextManager[BlockingPortal] | None = None - with self._lock: - assert self._portal_cm - assert self._leases > 0 - self._leases -= 1 - if not self._leases: - portal_cm = self._portal_cm - self._portal_cm = None - del self._portal - - if portal_cm: - portal_cm.__exit__(None, None, None) - - -@contextmanager -def start_blocking_portal( - backend: str = "asyncio", - backend_options: dict[str, Any] | None = None, - *, - name: str | None = None, -) -> Generator[BlockingPortal, Any, None]: - """ - Start a new event loop in a new thread and run a blocking portal in its main task. - - The parameters are the same as for :func:`~anyio.run`. - - :param backend: name of the backend - :param backend_options: backend options - :param name: name of the thread - :return: a context manager that yields a blocking portal - - .. versionchanged:: 3.0 - Usage as a context manager is now required. - - """ - - async def run_portal() -> None: - async with BlockingPortal() as portal_: - if name is None: - current_thread().name = f"{backend}-portal-{id(portal_):x}" - - future.set_result(portal_) - await portal_.sleep_until_stopped() - - def run_blocking_portal() -> None: - if future.set_running_or_notify_cancel(): - try: - run_eventloop( - run_portal, backend=backend, backend_options=backend_options - ) - except BaseException as exc: - if not future.done(): - future.set_exception(exc) - - future: Future[BlockingPortal] = Future() - thread = Thread(target=run_blocking_portal, daemon=True, name=name) - thread.start() - try: - cancel_remaining_tasks = False - portal = future.result() - try: - yield portal - except BaseException: - cancel_remaining_tasks = True - raise - finally: - try: - portal.call(portal.stop, cancel_remaining_tasks) - except RuntimeError: - pass - finally: - thread.join() - - -def check_cancelled() -> None: - """ - Check if the cancel scope of the host task's running the current worker thread has - been cancelled. - - If the host task's current cancel scope has indeed been cancelled, the - backend-specific cancellation exception will be raised. - - :raises RuntimeError: if the current thread was not spawned by - :func:`.to_thread.run_sync` - - """ - try: - token: EventLoopToken = threadlocals.current_token - except AttributeError: - raise NoEventLoopError( - "This function can only be called inside an AnyIO worker thread" - ) from None - - token.backend_class.check_cancelled() diff --git a/venv/lib/python3.10/site-packages/anyio/functools.py b/venv/lib/python3.10/site-packages/anyio/functools.py deleted file mode 100644 index b80afe6c81e5138c9ba439cd1b7d633eac154b21..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/functools.py +++ /dev/null @@ -1,375 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "AsyncCacheInfo", - "AsyncCacheParameters", - "AsyncLRUCacheWrapper", - "cache", - "lru_cache", - "reduce", -) - -import functools -import sys -from collections import OrderedDict -from collections.abc import ( - AsyncIterable, - Awaitable, - Callable, - Coroutine, - Hashable, - Iterable, -) -from functools import update_wrapper -from inspect import iscoroutinefunction -from typing import ( - Any, - Generic, - NamedTuple, - TypedDict, - TypeVar, - cast, - final, - overload, -) -from weakref import WeakKeyDictionary - -from ._core._synchronization import Lock -from .lowlevel import RunVar, checkpoint - -if sys.version_info >= (3, 11): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec - -T = TypeVar("T") -S = TypeVar("S") -P = ParamSpec("P") -lru_cache_items: RunVar[ - WeakKeyDictionary[ - AsyncLRUCacheWrapper[Any, Any], - OrderedDict[Hashable, tuple[_InitialMissingType, Lock] | tuple[Any, None]], - ] -] = RunVar("lru_cache_items") - - -class _InitialMissingType: - pass - - -initial_missing: _InitialMissingType = _InitialMissingType() - - -class AsyncCacheInfo(NamedTuple): - hits: int - misses: int - maxsize: int | None - currsize: int - - -class AsyncCacheParameters(TypedDict): - maxsize: int | None - typed: bool - always_checkpoint: bool - - -class _LRUMethodWrapper(Generic[T]): - def __init__(self, wrapper: AsyncLRUCacheWrapper[..., T], instance: object): - self.__wrapper = wrapper - self.__instance = instance - - def cache_info(self) -> AsyncCacheInfo: - return self.__wrapper.cache_info() - - def cache_parameters(self) -> AsyncCacheParameters: - return self.__wrapper.cache_parameters() - - def cache_clear(self) -> None: - self.__wrapper.cache_clear() - - async def __call__(self, *args: Any, **kwargs: Any) -> T: - if self.__instance is None: - return await self.__wrapper(*args, **kwargs) - - return await self.__wrapper(self.__instance, *args, **kwargs) - - -@final -class AsyncLRUCacheWrapper(Generic[P, T]): - def __init__( - self, - func: Callable[P, Awaitable[T]], - maxsize: int | None, - typed: bool, - always_checkpoint: bool, - ): - self.__wrapped__ = func - self._hits: int = 0 - self._misses: int = 0 - self._maxsize = max(maxsize, 0) if maxsize is not None else None - self._currsize: int = 0 - self._typed = typed - self._always_checkpoint = always_checkpoint - update_wrapper(self, func) - - def cache_info(self) -> AsyncCacheInfo: - return AsyncCacheInfo(self._hits, self._misses, self._maxsize, self._currsize) - - def cache_parameters(self) -> AsyncCacheParameters: - return { - "maxsize": self._maxsize, - "typed": self._typed, - "always_checkpoint": self._always_checkpoint, - } - - def cache_clear(self) -> None: - if cache := lru_cache_items.get(None): - cache.pop(self, None) - self._hits = self._misses = self._currsize = 0 - - async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: - # Easy case first: if maxsize == 0, no caching is done - if self._maxsize == 0: - value = await self.__wrapped__(*args, **kwargs) - self._misses += 1 - return value - - # The key is constructed as a flat tuple to avoid memory overhead - key: tuple[Any, ...] = args - if kwargs: - # initial_missing is used as a separator - key += (initial_missing,) + sum(kwargs.items(), ()) - - if self._typed: - key += tuple(type(arg) for arg in args) - if kwargs: - key += (initial_missing,) + tuple(type(val) for val in kwargs.values()) - - try: - cache = lru_cache_items.get() - except LookupError: - cache = WeakKeyDictionary() - lru_cache_items.set(cache) - - try: - cache_entry = cache[self] - except KeyError: - cache_entry = cache[self] = OrderedDict() - - cached_value: T | _InitialMissingType - try: - cached_value, lock = cache_entry[key] - except KeyError: - # We're the first task to call this function - cached_value, lock = ( - initial_missing, - Lock(fast_acquire=not self._always_checkpoint), - ) - cache_entry[key] = cached_value, lock - - if lock is None: - # The value was already cached - self._hits += 1 - cache_entry.move_to_end(key) - if self._always_checkpoint: - await checkpoint() - - return cast(T, cached_value) - - async with lock: - # Check if another task filled the cache while we acquired the lock - if (cached_value := cache_entry[key][0]) is initial_missing: - self._misses += 1 - if self._maxsize is not None and self._currsize >= self._maxsize: - cache_entry.popitem(last=False) - else: - self._currsize += 1 - - value = await self.__wrapped__(*args, **kwargs) - cache_entry[key] = value, None - else: - # Another task filled the cache while we were waiting for the lock - self._hits += 1 - cache_entry.move_to_end(key) - value = cast(T, cached_value) - - return value - - def __get__( - self, instance: object, owner: type | None = None - ) -> _LRUMethodWrapper[T]: - wrapper = _LRUMethodWrapper(self, instance) - update_wrapper(wrapper, self.__wrapped__) - return wrapper - - -class _LRUCacheWrapper(Generic[T]): - def __init__(self, maxsize: int | None, typed: bool, always_checkpoint: bool): - self._maxsize = maxsize - self._typed = typed - self._always_checkpoint = always_checkpoint - - @overload - def __call__( # type: ignore[overload-overlap] - self, func: Callable[P, Coroutine[Any, Any, T]], / - ) -> AsyncLRUCacheWrapper[P, T]: ... - - @overload - def __call__( - self, func: Callable[..., T], / - ) -> functools._lru_cache_wrapper[T]: ... - - def __call__( - self, f: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T], / - ) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]: - if iscoroutinefunction(f): - return AsyncLRUCacheWrapper( - f, self._maxsize, self._typed, self._always_checkpoint - ) - - return functools.lru_cache(maxsize=self._maxsize, typed=self._typed)(f) # type: ignore[arg-type] - - -@overload -def cache( # type: ignore[overload-overlap] - func: Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T]: ... - - -@overload -def cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... - - -def cache( - func: Callable[..., T] | Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]: - """ - A convenient shortcut for :func:`lru_cache` with ``maxsize=None``. - - This is the asynchronous equivalent to :func:`functools.cache`. - - """ - return lru_cache(maxsize=None)(func) - - -@overload -def lru_cache( - *, maxsize: int | None = ..., typed: bool = ..., always_checkpoint: bool = ... -) -> _LRUCacheWrapper[Any]: ... - - -@overload -def lru_cache( # type: ignore[overload-overlap] - func: Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T]: ... - - -@overload -def lru_cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... - - -def lru_cache( - func: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T] | None = None, - /, - *, - maxsize: int | None = 128, - typed: bool = False, - always_checkpoint: bool = False, -) -> ( - AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T] | _LRUCacheWrapper[Any] -): - """ - An asynchronous version of :func:`functools.lru_cache`. - - If a synchronous function is passed, the standard library - :func:`functools.lru_cache` is applied instead. - - :param always_checkpoint: if ``True``, every call to the cached function will be - guaranteed to yield control to the event loop at least once - - .. note:: Caches and locks are managed on a per-event loop basis. - - """ - if func is None: - return _LRUCacheWrapper[Any](maxsize, typed, always_checkpoint) - - if not callable(func): - raise TypeError("the first argument must be callable") - - return _LRUCacheWrapper[T](maxsize, typed, always_checkpoint)(func) - - -@overload -async def reduce( - function: Callable[[T, S], Awaitable[T]], - iterable: Iterable[S] | AsyncIterable[S], - /, - initial: T, -) -> T: ... - - -@overload -async def reduce( - function: Callable[[T, T], Awaitable[T]], - iterable: Iterable[T] | AsyncIterable[T], - /, -) -> T: ... - - -async def reduce( # type: ignore[misc] - function: Callable[[T, T], Awaitable[T]] | Callable[[T, S], Awaitable[T]], - iterable: Iterable[T] | Iterable[S] | AsyncIterable[T] | AsyncIterable[S], - /, - initial: T | _InitialMissingType = initial_missing, -) -> T: - """ - Asynchronous version of :func:`functools.reduce`. - - :param function: a coroutine function that takes two arguments: the accumulated - value and the next element from the iterable - :param iterable: an iterable or async iterable - :param initial: the initial value (if missing, the first element of the iterable is - used as the initial value) - - """ - element: Any - function_called = False - if isinstance(iterable, AsyncIterable): - async_it = iterable.__aiter__() - if initial is initial_missing: - try: - value = cast(T, await async_it.__anext__()) - except StopAsyncIteration: - raise TypeError( - "reduce() of empty sequence with no initial value" - ) from None - else: - value = cast(T, initial) - - async for element in async_it: - value = await function(value, element) - function_called = True - elif isinstance(iterable, Iterable): - it = iter(iterable) - if initial is initial_missing: - try: - value = cast(T, next(it)) - except StopIteration: - raise TypeError( - "reduce() of empty sequence with no initial value" - ) from None - else: - value = cast(T, initial) - - for element in it: - value = await function(value, element) - function_called = True - else: - raise TypeError("reduce() argument 2 must be an iterable or async iterable") - - # Make sure there is at least one checkpoint, even if an empty iterable and an - # initial value were given - if not function_called: - await checkpoint() - - return value diff --git a/venv/lib/python3.10/site-packages/anyio/lowlevel.py b/venv/lib/python3.10/site-packages/anyio/lowlevel.py deleted file mode 100644 index ffbb75a7079aa4b1a13318641c1e1299e7bc1827..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/lowlevel.py +++ /dev/null @@ -1,196 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "EventLoopToken", - "RunvarToken", - "RunVar", - "checkpoint", - "checkpoint_if_cancelled", - "cancel_shielded_checkpoint", - "current_token", -) - -import enum -from dataclasses import dataclass -from types import TracebackType -from typing import Any, Generic, Literal, TypeVar, final, overload -from weakref import WeakKeyDictionary - -from ._core._eventloop import get_async_backend -from .abc import AsyncBackend - -T = TypeVar("T") -D = TypeVar("D") - - -async def checkpoint() -> None: - """ - Check for cancellation and allow the scheduler to switch to another task. - - Equivalent to (but more efficient than):: - - await checkpoint_if_cancelled() - await cancel_shielded_checkpoint() - - .. versionadded:: 3.0 - - """ - await get_async_backend().checkpoint() - - -async def checkpoint_if_cancelled() -> None: - """ - Enter a checkpoint if the enclosing cancel scope has been cancelled. - - This does not allow the scheduler to switch to a different task. - - .. versionadded:: 3.0 - - """ - await get_async_backend().checkpoint_if_cancelled() - - -async def cancel_shielded_checkpoint() -> None: - """ - Allow the scheduler to switch to another task but without checking for cancellation. - - Equivalent to (but potentially more efficient than):: - - with CancelScope(shield=True): - await checkpoint() - - .. versionadded:: 3.0 - - """ - await get_async_backend().cancel_shielded_checkpoint() - - -@final -@dataclass(frozen=True, repr=False) -class EventLoopToken: - """ - An opaque object that holds a reference to an event loop. - - .. versionadded:: 4.11.0 - """ - - backend_class: type[AsyncBackend] - native_token: object - - -def current_token() -> EventLoopToken: - """ - Return a token object that can be used to call code in the current event loop from - another thread. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. versionadded:: 4.11.0 - - """ - backend_class = get_async_backend() - raw_token = backend_class.current_token() - return EventLoopToken(backend_class, raw_token) - - -_run_vars: WeakKeyDictionary[object, dict[RunVar[Any], Any]] = WeakKeyDictionary() - - -class _NoValueSet(enum.Enum): - NO_VALUE_SET = enum.auto() - - -class RunvarToken(Generic[T]): - __slots__ = "_var", "_value", "_redeemed" - - def __init__(self, var: RunVar[T], value: T | Literal[_NoValueSet.NO_VALUE_SET]): - self._var = var - self._value: T | Literal[_NoValueSet.NO_VALUE_SET] = value - self._redeemed = False - - def __enter__(self) -> RunvarToken[T]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._var.reset(self) - - -class RunVar(Generic[T]): - """ - Like a :class:`~contextvars.ContextVar`, except scoped to the running event loop. - - Can be used as a context manager, Just like :class:`~contextvars.ContextVar`, that - will reset the variable to its previous value when the context block is exited. - """ - - __slots__ = "_name", "_default" - - NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET - - def __init__( - self, name: str, default: T | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET - ): - self._name = name - self._default = default - - @property - def _current_vars(self) -> dict[RunVar[T], T]: - native_token = current_token().native_token - try: - return _run_vars[native_token] - except KeyError: - run_vars = _run_vars[native_token] = {} - return run_vars - - @overload - def get(self, default: D) -> T | D: ... - - @overload - def get(self) -> T: ... - - def get( - self, default: D | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET - ) -> T | D: - try: - return self._current_vars[self] - except KeyError: - if default is not RunVar.NO_VALUE_SET: - return default - elif self._default is not RunVar.NO_VALUE_SET: - return self._default - - raise LookupError( - f'Run variable "{self._name}" has no value and no default set' - ) - - def set(self, value: T) -> RunvarToken[T]: - current_vars = self._current_vars - token = RunvarToken(self, current_vars.get(self, RunVar.NO_VALUE_SET)) - current_vars[self] = value - return token - - def reset(self, token: RunvarToken[T]) -> None: - if token._var is not self: - raise ValueError("This token does not belong to this RunVar") - - if token._redeemed: - raise ValueError("This token has already been used") - - if token._value is _NoValueSet.NO_VALUE_SET: - try: - del self._current_vars[self] - except KeyError: - pass - else: - self._current_vars[self] = token._value - - token._redeemed = True - - def __repr__(self) -> str: - return f"" diff --git a/venv/lib/python3.10/site-packages/anyio/py.typed b/venv/lib/python3.10/site-packages/anyio/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/anyio/pytest_plugin.py b/venv/lib/python3.10/site-packages/anyio/pytest_plugin.py deleted file mode 100644 index 4222816ab72f6dc96e16e43e06ae6a8b4059b3cd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/pytest_plugin.py +++ /dev/null @@ -1,302 +0,0 @@ -from __future__ import annotations - -import socket -import sys -from collections.abc import Callable, Generator, Iterator -from contextlib import ExitStack, contextmanager -from inspect import isasyncgenfunction, iscoroutinefunction, ismethod -from typing import Any, cast - -import pytest -from _pytest.fixtures import SubRequest -from _pytest.outcomes import Exit - -from . import get_available_backends -from ._core._eventloop import ( - current_async_library, - get_async_backend, - reset_current_async_library, - set_current_async_library, -) -from ._core._exceptions import iterate_exceptions -from .abc import TestRunner - -if sys.version_info < (3, 11): - from exceptiongroup import ExceptionGroup - -_current_runner: TestRunner | None = None -_runner_stack: ExitStack | None = None -_runner_leases = 0 - - -def extract_backend_and_options(backend: object) -> tuple[str, dict[str, Any]]: - if isinstance(backend, str): - return backend, {} - elif isinstance(backend, tuple) and len(backend) == 2: - if isinstance(backend[0], str) and isinstance(backend[1], dict): - return cast(tuple[str, dict[str, Any]], backend) - - raise TypeError("anyio_backend must be either a string or tuple of (string, dict)") - - -@contextmanager -def get_runner( - backend_name: str, backend_options: dict[str, Any] -) -> Iterator[TestRunner]: - global _current_runner, _runner_leases, _runner_stack - if _current_runner is None: - asynclib = get_async_backend(backend_name) - _runner_stack = ExitStack() - if current_async_library() is None: - # Since we're in control of the event loop, we can cache the name of the - # async library - token = set_current_async_library(backend_name) - _runner_stack.callback(reset_current_async_library, token) - - backend_options = backend_options or {} - _current_runner = _runner_stack.enter_context( - asynclib.create_test_runner(backend_options) - ) - - _runner_leases += 1 - try: - yield _current_runner - finally: - _runner_leases -= 1 - if not _runner_leases: - assert _runner_stack is not None - _runner_stack.close() - _runner_stack = _current_runner = None - - -def pytest_addoption(parser: pytest.Parser) -> None: - parser.addini( - "anyio_mode", - default="strict", - help='AnyIO plugin mode (either "strict" or "auto")', - ) - - -def pytest_configure(config: pytest.Config) -> None: - config.addinivalue_line( - "markers", - "anyio: mark the (coroutine function) test to be run asynchronously via anyio.", - ) - if ( - config.getini("anyio_mode") == "auto" - and config.pluginmanager.has_plugin("asyncio") - and config.getini("asyncio_mode") == "auto" - ): - config.issue_config_time_warning( - pytest.PytestConfigWarning( - "AnyIO auto mode has been enabled together with pytest-asyncio auto " - "mode. This may cause unexpected behavior." - ), - 1, - ) - - -@pytest.hookimpl(hookwrapper=True) -def pytest_fixture_setup(fixturedef: Any, request: Any) -> Generator[Any]: - def wrapper(anyio_backend: Any, request: SubRequest, **kwargs: Any) -> Any: - # Rebind any fixture methods to the request instance - if ( - request.instance - and ismethod(func) - and type(func.__self__) is type(request.instance) - ): - local_func = func.__func__.__get__(request.instance) - else: - local_func = func - - backend_name, backend_options = extract_backend_and_options(anyio_backend) - if has_backend_arg: - kwargs["anyio_backend"] = anyio_backend - - if has_request_arg: - kwargs["request"] = request - - with get_runner(backend_name, backend_options) as runner: - if isasyncgenfunction(local_func): - yield from runner.run_asyncgen_fixture(local_func, kwargs) - else: - yield runner.run_fixture(local_func, kwargs) - - # Only apply this to coroutine functions and async generator functions in requests - # that involve the anyio_backend fixture - func = fixturedef.func - if isasyncgenfunction(func) or iscoroutinefunction(func): - if "anyio_backend" in request.fixturenames: - fixturedef.func = wrapper - original_argname = fixturedef.argnames - - if not (has_backend_arg := "anyio_backend" in fixturedef.argnames): - fixturedef.argnames += ("anyio_backend",) - - if not (has_request_arg := "request" in fixturedef.argnames): - fixturedef.argnames += ("request",) - - try: - return (yield) - finally: - fixturedef.func = func - fixturedef.argnames = original_argname - - return (yield) - - -@pytest.hookimpl(tryfirst=True) -def pytest_pycollect_makeitem( - collector: pytest.Module | pytest.Class, name: str, obj: object -) -> None: - if collector.istestfunction(obj, name): - inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj - if iscoroutinefunction(inner_func): - anyio_auto_mode = collector.config.getini("anyio_mode") == "auto" - marker = collector.get_closest_marker("anyio") - own_markers = getattr(obj, "pytestmark", ()) - if ( - anyio_auto_mode - or marker - or any(marker.name == "anyio" for marker in own_markers) - ): - pytest.mark.usefixtures("anyio_backend")(obj) - - -@pytest.hookimpl(tryfirst=True) -def pytest_pyfunc_call(pyfuncitem: Any) -> bool | None: - def run_with_hypothesis(**kwargs: Any) -> None: - with get_runner(backend_name, backend_options) as runner: - runner.run_test(original_func, kwargs) - - backend = pyfuncitem.funcargs.get("anyio_backend") - if backend: - backend_name, backend_options = extract_backend_and_options(backend) - - if hasattr(pyfuncitem.obj, "hypothesis"): - # Wrap the inner test function unless it's already wrapped - original_func = pyfuncitem.obj.hypothesis.inner_test - if original_func.__qualname__ != run_with_hypothesis.__qualname__: - if iscoroutinefunction(original_func): - pyfuncitem.obj.hypothesis.inner_test = run_with_hypothesis - - return None - - if iscoroutinefunction(pyfuncitem.obj): - funcargs = pyfuncitem.funcargs - testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} - with get_runner(backend_name, backend_options) as runner: - try: - runner.run_test(pyfuncitem.obj, testargs) - except ExceptionGroup as excgrp: - for exc in iterate_exceptions(excgrp): - if isinstance(exc, (Exit, KeyboardInterrupt, SystemExit)): - raise exc from excgrp - - raise - - return True - - return None - - -@pytest.fixture(scope="module", params=get_available_backends()) -def anyio_backend(request: Any) -> Any: - return request.param - - -@pytest.fixture -def anyio_backend_name(anyio_backend: Any) -> str: - if isinstance(anyio_backend, str): - return anyio_backend - else: - return anyio_backend[0] - - -@pytest.fixture -def anyio_backend_options(anyio_backend: Any) -> dict[str, Any]: - if isinstance(anyio_backend, str): - return {} - else: - return anyio_backend[1] - - -class FreePortFactory: - """ - Manages port generation based on specified socket kind, ensuring no duplicate - ports are generated. - - This class provides functionality for generating available free ports on the - system. It is initialized with a specific socket kind and can generate ports - for given address families while avoiding reuse of previously generated ports. - - Users should not instantiate this class directly, but use the - ``free_tcp_port_factory`` and ``free_udp_port_factory`` fixtures instead. For simple - uses cases, ``free_tcp_port`` and ``free_udp_port`` can be used instead. - """ - - def __init__(self, kind: socket.SocketKind) -> None: - self._kind = kind - self._generated = set[int]() - - @property - def kind(self) -> socket.SocketKind: - """ - The type of socket connection (e.g., :data:`~socket.SOCK_STREAM` or - :data:`~socket.SOCK_DGRAM`) used to bind for checking port availability - - """ - return self._kind - - def __call__(self, family: socket.AddressFamily | None = None) -> int: - """ - Return an unbound port for the given address family. - - :param family: if omitted, both IPv4 and IPv6 addresses will be tried - :return: a port number - - """ - if family is not None: - families = [family] - else: - families = [socket.AF_INET] - if socket.has_ipv6: - families.append(socket.AF_INET6) - - while True: - port = 0 - with ExitStack() as stack: - for family in families: - sock = stack.enter_context(socket.socket(family, self._kind)) - addr = "::1" if family == socket.AF_INET6 else "127.0.0.1" - try: - sock.bind((addr, port)) - except OSError: - break - - if not port: - port = sock.getsockname()[1] - else: - if port not in self._generated: - self._generated.add(port) - return port - - -@pytest.fixture(scope="session") -def free_tcp_port_factory() -> FreePortFactory: - return FreePortFactory(socket.SOCK_STREAM) - - -@pytest.fixture(scope="session") -def free_udp_port_factory() -> FreePortFactory: - return FreePortFactory(socket.SOCK_DGRAM) - - -@pytest.fixture -def free_tcp_port(free_tcp_port_factory: Callable[[], int]) -> int: - return free_tcp_port_factory() - - -@pytest.fixture -def free_udp_port(free_udp_port_factory: Callable[[], int]) -> int: - return free_udp_port_factory() diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__init__.py b/venv/lib/python3.10/site-packages/anyio/streams/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index cfaeb2cf5ad094850d479b9ae6e8aa384464f03e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/buffered.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/buffered.cpython-310.pyc deleted file mode 100644 index a7faee2257fdf03b9abf8757024fca30428b56ef..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/buffered.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/file.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/file.cpython-310.pyc deleted file mode 100644 index 5ff3069e485865b1f94135c722c8641f6fc6596b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/file.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/memory.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/memory.cpython-310.pyc deleted file mode 100644 index 443e9d662d678c011da02231034ac66892b5b10e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/memory.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/stapled.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/stapled.cpython-310.pyc deleted file mode 100644 index 639ce0e29e1325bff2619211c2a0628a9ddf24bc..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/stapled.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/text.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/text.cpython-310.pyc deleted file mode 100644 index 4219a6d992269cdbf8a6315757d5d8149d8f1948..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/text.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/tls.cpython-310.pyc b/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/tls.cpython-310.pyc deleted file mode 100644 index 2eddd36ea246b71bdf5abe0ea09d1dda93e07ecd..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/anyio/streams/__pycache__/tls.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/anyio/streams/buffered.py b/venv/lib/python3.10/site-packages/anyio/streams/buffered.py deleted file mode 100644 index 57c7cd749bfb94bbe7a992aa9a05af268a841d3d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/streams/buffered.py +++ /dev/null @@ -1,188 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "BufferedByteReceiveStream", - "BufferedByteStream", - "BufferedConnectable", -) - -import sys -from collections.abc import Callable, Iterable, Mapping -from dataclasses import dataclass, field -from typing import Any, SupportsIndex - -from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead -from ..abc import ( - AnyByteReceiveStream, - AnyByteStream, - AnyByteStreamConnectable, - ByteReceiveStream, - ByteStream, - ByteStreamConnectable, -) - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - - -@dataclass(eq=False) -class BufferedByteReceiveStream(ByteReceiveStream): - """ - Wraps any bytes-based receive stream and uses a buffer to provide sophisticated - receiving capabilities in the form of a byte stream. - """ - - receive_stream: AnyByteReceiveStream - _buffer: bytearray = field(init=False, default_factory=bytearray) - _closed: bool = field(init=False, default=False) - - async def aclose(self) -> None: - await self.receive_stream.aclose() - self._closed = True - - @property - def buffer(self) -> bytes: - """The bytes currently in the buffer.""" - return bytes(self._buffer) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.receive_stream.extra_attributes - - def feed_data(self, data: Iterable[SupportsIndex], /) -> None: - """ - Append data directly into the buffer. - - Any data in the buffer will be consumed by receive operations before receiving - anything from the wrapped stream. - - :param data: the data to append to the buffer (can be bytes or anything else - that supports ``__index__()``) - - """ - self._buffer.extend(data) - - async def receive(self, max_bytes: int = 65536) -> bytes: - if self._closed: - raise ClosedResourceError - - if self._buffer: - chunk = bytes(self._buffer[:max_bytes]) - del self._buffer[:max_bytes] - return chunk - elif isinstance(self.receive_stream, ByteReceiveStream): - return await self.receive_stream.receive(max_bytes) - else: - # With a bytes-oriented object stream, we need to handle any surplus bytes - # we get from the receive() call - chunk = await self.receive_stream.receive() - if len(chunk) > max_bytes: - # Save the surplus bytes in the buffer - self._buffer.extend(chunk[max_bytes:]) - return chunk[:max_bytes] - else: - return chunk - - async def receive_exactly(self, nbytes: int) -> bytes: - """ - Read exactly the given amount of bytes from the stream. - - :param nbytes: the number of bytes to read - :return: the bytes read - :raises ~anyio.IncompleteRead: if the stream was closed before the requested - amount of bytes could be read from the stream - - """ - while True: - remaining = nbytes - len(self._buffer) - if remaining <= 0: - retval = self._buffer[:nbytes] - del self._buffer[:nbytes] - return bytes(retval) - - try: - if isinstance(self.receive_stream, ByteReceiveStream): - chunk = await self.receive_stream.receive(remaining) - else: - chunk = await self.receive_stream.receive() - except EndOfStream as exc: - raise IncompleteRead from exc - - self._buffer.extend(chunk) - - async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes: - """ - Read from the stream until the delimiter is found or max_bytes have been read. - - :param delimiter: the marker to look for in the stream - :param max_bytes: maximum number of bytes that will be read before raising - :exc:`~anyio.DelimiterNotFound` - :return: the bytes read (not including the delimiter) - :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter - was found - :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the - bytes read up to the maximum allowed - - """ - delimiter_size = len(delimiter) - offset = 0 - while True: - # Check if the delimiter can be found in the current buffer - index = self._buffer.find(delimiter, offset) - if index >= 0: - found = self._buffer[:index] - del self._buffer[: index + len(delimiter) :] - return bytes(found) - - # Check if the buffer is already at or over the limit - if len(self._buffer) >= max_bytes: - raise DelimiterNotFound(max_bytes) - - # Read more data into the buffer from the socket - try: - data = await self.receive_stream.receive() - except EndOfStream as exc: - raise IncompleteRead from exc - - # Move the offset forward and add the new data to the buffer - offset = max(len(self._buffer) - delimiter_size + 1, 0) - self._buffer.extend(data) - - -class BufferedByteStream(BufferedByteReceiveStream, ByteStream): - """ - A full-duplex variant of :class:`BufferedByteReceiveStream`. All writes are passed - through to the wrapped stream as-is. - """ - - def __init__(self, stream: AnyByteStream): - """ - :param stream: the stream to be wrapped - - """ - super().__init__(stream) - self._stream = stream - - @override - async def send_eof(self) -> None: - await self._stream.send_eof() - - @override - async def send(self, item: bytes) -> None: - await self._stream.send(item) - - -class BufferedConnectable(ByteStreamConnectable): - def __init__(self, connectable: AnyByteStreamConnectable): - """ - :param connectable: the connectable to wrap - - """ - self.connectable = connectable - - @override - async def connect(self) -> BufferedByteStream: - stream = await self.connectable.connect() - return BufferedByteStream(stream) diff --git a/venv/lib/python3.10/site-packages/anyio/streams/file.py b/venv/lib/python3.10/site-packages/anyio/streams/file.py deleted file mode 100644 index 82d2da8965ab4281ef0b554f7b8cae857a21bde5..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/streams/file.py +++ /dev/null @@ -1,154 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "FileReadStream", - "FileStreamAttribute", - "FileWriteStream", -) - -from collections.abc import Callable, Mapping -from io import SEEK_SET, UnsupportedOperation -from os import PathLike -from pathlib import Path -from typing import Any, BinaryIO, cast - -from .. import ( - BrokenResourceError, - ClosedResourceError, - EndOfStream, - TypedAttributeSet, - to_thread, - typed_attribute, -) -from ..abc import ByteReceiveStream, ByteSendStream - - -class FileStreamAttribute(TypedAttributeSet): - #: the open file descriptor - file: BinaryIO = typed_attribute() - #: the path of the file on the file system, if available (file must be a real file) - path: Path = typed_attribute() - #: the file number, if available (file must be a real file or a TTY) - fileno: int = typed_attribute() - - -class _BaseFileStream: - def __init__(self, file: BinaryIO): - self._file = file - - async def aclose(self) -> None: - await to_thread.run_sync(self._file.close) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - attributes: dict[Any, Callable[[], Any]] = { - FileStreamAttribute.file: lambda: self._file, - } - - if hasattr(self._file, "name"): - attributes[FileStreamAttribute.path] = lambda: Path(self._file.name) - - try: - self._file.fileno() - except UnsupportedOperation: - pass - else: - attributes[FileStreamAttribute.fileno] = lambda: self._file.fileno() - - return attributes - - -class FileReadStream(_BaseFileStream, ByteReceiveStream): - """ - A byte stream that reads from a file in the file system. - - :param file: a file that has been opened for reading in binary mode - - .. versionadded:: 3.0 - """ - - @classmethod - async def from_path(cls, path: str | PathLike[str]) -> FileReadStream: - """ - Create a file read stream by opening the given file. - - :param path: path of the file to read from - - """ - file = await to_thread.run_sync(Path(path).open, "rb") - return cls(cast(BinaryIO, file)) - - async def receive(self, max_bytes: int = 65536) -> bytes: - try: - data = await to_thread.run_sync(self._file.read, max_bytes) - except ValueError: - raise ClosedResourceError from None - except OSError as exc: - raise BrokenResourceError from exc - - if data: - return data - else: - raise EndOfStream - - async def seek(self, position: int, whence: int = SEEK_SET) -> int: - """ - Seek the file to the given position. - - .. seealso:: :meth:`io.IOBase.seek` - - .. note:: Not all file descriptors are seekable. - - :param position: position to seek the file to - :param whence: controls how ``position`` is interpreted - :return: the new absolute position - :raises OSError: if the file is not seekable - - """ - return await to_thread.run_sync(self._file.seek, position, whence) - - async def tell(self) -> int: - """ - Return the current stream position. - - .. note:: Not all file descriptors are seekable. - - :return: the current absolute position - :raises OSError: if the file is not seekable - - """ - return await to_thread.run_sync(self._file.tell) - - -class FileWriteStream(_BaseFileStream, ByteSendStream): - """ - A byte stream that writes to a file in the file system. - - :param file: a file that has been opened for writing in binary mode - - .. versionadded:: 3.0 - """ - - @classmethod - async def from_path( - cls, path: str | PathLike[str], append: bool = False - ) -> FileWriteStream: - """ - Create a file write stream by opening the given file for writing. - - :param path: path of the file to write to - :param append: if ``True``, open the file for appending; if ``False``, any - existing file at the given path will be truncated - - """ - mode = "ab" if append else "wb" - file = await to_thread.run_sync(Path(path).open, mode) - return cls(cast(BinaryIO, file)) - - async def send(self, item: bytes) -> None: - try: - await to_thread.run_sync(self._file.write, item) - except ValueError: - raise ClosedResourceError from None - except OSError as exc: - raise BrokenResourceError from exc diff --git a/venv/lib/python3.10/site-packages/anyio/streams/memory.py b/venv/lib/python3.10/site-packages/anyio/streams/memory.py deleted file mode 100644 index a3fa0c3d9783f34fb5225938f6ce5d1d31b9b85c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/streams/memory.py +++ /dev/null @@ -1,325 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "MemoryObjectReceiveStream", - "MemoryObjectSendStream", - "MemoryObjectStreamStatistics", -) - -import warnings -from collections import OrderedDict, deque -from dataclasses import dataclass, field -from types import TracebackType -from typing import Generic, NamedTuple, TypeVar - -from .. import ( - BrokenResourceError, - ClosedResourceError, - EndOfStream, - WouldBlock, -) -from .._core._testing import TaskInfo, get_current_task -from ..abc import Event, ObjectReceiveStream, ObjectSendStream -from ..lowlevel import checkpoint - -T_Item = TypeVar("T_Item") -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True) - - -class MemoryObjectStreamStatistics(NamedTuple): - current_buffer_used: int #: number of items stored in the buffer - #: maximum number of items that can be stored on this stream (or :data:`math.inf`) - max_buffer_size: float - open_send_streams: int #: number of unclosed clones of the send stream - open_receive_streams: int #: number of unclosed clones of the receive stream - #: number of tasks blocked on :meth:`MemoryObjectSendStream.send` - tasks_waiting_send: int - #: number of tasks blocked on :meth:`MemoryObjectReceiveStream.receive` - tasks_waiting_receive: int - - -@dataclass(eq=False) -class _MemoryObjectItemReceiver(Generic[T_Item]): - task_info: TaskInfo = field(init=False, default_factory=get_current_task) - item: T_Item = field(init=False) - - def __repr__(self) -> str: - # When item is not defined, we get following error with default __repr__: - # AttributeError: 'MemoryObjectItemReceiver' object has no attribute 'item' - item = getattr(self, "item", None) - return f"{self.__class__.__name__}(task_info={self.task_info}, item={item!r})" - - -@dataclass(eq=False) -class _MemoryObjectStreamState(Generic[T_Item]): - max_buffer_size: float = field() - buffer: deque[T_Item] = field(init=False, default_factory=deque) - open_send_channels: int = field(init=False, default=0) - open_receive_channels: int = field(init=False, default=0) - waiting_receivers: OrderedDict[Event, _MemoryObjectItemReceiver[T_Item]] = field( - init=False, default_factory=OrderedDict - ) - waiting_senders: OrderedDict[Event, T_Item] = field( - init=False, default_factory=OrderedDict - ) - - def statistics(self) -> MemoryObjectStreamStatistics: - return MemoryObjectStreamStatistics( - len(self.buffer), - self.max_buffer_size, - self.open_send_channels, - self.open_receive_channels, - len(self.waiting_senders), - len(self.waiting_receivers), - ) - - -@dataclass(eq=False) -class MemoryObjectReceiveStream(Generic[T_co], ObjectReceiveStream[T_co]): - _state: _MemoryObjectStreamState[T_co] - _closed: bool = field(init=False, default=False) - - def __post_init__(self) -> None: - self._state.open_receive_channels += 1 - - def receive_nowait(self) -> T_co: - """ - Receive the next item if it can be done without waiting. - - :return: the received item - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.EndOfStream: if the buffer is empty and this stream has been - closed from the sending end - :raises ~anyio.WouldBlock: if there are no items in the buffer and no tasks - waiting to send - - """ - if self._closed: - raise ClosedResourceError - - if self._state.waiting_senders: - # Get the item from the next sender - send_event, item = self._state.waiting_senders.popitem(last=False) - self._state.buffer.append(item) - send_event.set() - - if self._state.buffer: - return self._state.buffer.popleft() - elif not self._state.open_send_channels: - raise EndOfStream - - raise WouldBlock - - async def receive(self) -> T_co: - await checkpoint() - try: - return self.receive_nowait() - except WouldBlock: - # Add ourselves in the queue - receive_event = Event() - receiver = _MemoryObjectItemReceiver[T_co]() - self._state.waiting_receivers[receive_event] = receiver - - try: - await receive_event.wait() - finally: - self._state.waiting_receivers.pop(receive_event, None) - - try: - return receiver.item - except AttributeError: - raise EndOfStream from None - - def clone(self) -> MemoryObjectReceiveStream[T_co]: - """ - Create a clone of this receive stream. - - Each clone can be closed separately. Only when all clones have been closed will - the receiving end of the memory stream be considered closed by the sending ends. - - :return: the cloned stream - - """ - if self._closed: - raise ClosedResourceError - - return MemoryObjectReceiveStream(_state=self._state) - - def close(self) -> None: - """ - Close the stream. - - This works the exact same way as :meth:`aclose`, but is provided as a special - case for the benefit of synchronous callbacks. - - """ - if not self._closed: - self._closed = True - self._state.open_receive_channels -= 1 - if self._state.open_receive_channels == 0: - send_events = list(self._state.waiting_senders.keys()) - for event in send_events: - event.set() - - async def aclose(self) -> None: - self.close() - - def statistics(self) -> MemoryObjectStreamStatistics: - """ - Return statistics about the current state of this stream. - - .. versionadded:: 3.0 - """ - return self._state.statistics() - - def __enter__(self) -> MemoryObjectReceiveStream[T_co]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def __del__(self) -> None: - if not self._closed: - warnings.warn( - f"Unclosed <{self.__class__.__name__} at {id(self):x}>", - ResourceWarning, - stacklevel=1, - source=self, - ) - - -@dataclass(eq=False) -class MemoryObjectSendStream(Generic[T_contra], ObjectSendStream[T_contra]): - _state: _MemoryObjectStreamState[T_contra] - _closed: bool = field(init=False, default=False) - - def __post_init__(self) -> None: - self._state.open_send_channels += 1 - - def send_nowait(self, item: T_contra) -> None: - """ - Send an item immediately if it can be done without waiting. - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.BrokenResourceError: if the stream has been closed from the - receiving end - :raises ~anyio.WouldBlock: if the buffer is full and there are no tasks waiting - to receive - - """ - if self._closed: - raise ClosedResourceError - if not self._state.open_receive_channels: - raise BrokenResourceError - - while self._state.waiting_receivers: - receive_event, receiver = self._state.waiting_receivers.popitem(last=False) - if not receiver.task_info.has_pending_cancellation(): - receiver.item = item - receive_event.set() - return - - if len(self._state.buffer) < self._state.max_buffer_size: - self._state.buffer.append(item) - else: - raise WouldBlock - - async def send(self, item: T_contra) -> None: - """ - Send an item to the stream. - - If the buffer is full, this method blocks until there is again room in the - buffer or the item can be sent directly to a receiver. - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.BrokenResourceError: if the stream has been closed from the - receiving end - - """ - await checkpoint() - try: - self.send_nowait(item) - except WouldBlock: - # Wait until there's someone on the receiving end - send_event = Event() - self._state.waiting_senders[send_event] = item - try: - await send_event.wait() - except BaseException: - self._state.waiting_senders.pop(send_event, None) - raise - - if send_event in self._state.waiting_senders: - del self._state.waiting_senders[send_event] - raise BrokenResourceError from None - - def clone(self) -> MemoryObjectSendStream[T_contra]: - """ - Create a clone of this send stream. - - Each clone can be closed separately. Only when all clones have been closed will - the sending end of the memory stream be considered closed by the receiving ends. - - :return: the cloned stream - - """ - if self._closed: - raise ClosedResourceError - - return MemoryObjectSendStream(_state=self._state) - - def close(self) -> None: - """ - Close the stream. - - This works the exact same way as :meth:`aclose`, but is provided as a special - case for the benefit of synchronous callbacks. - - """ - if not self._closed: - self._closed = True - self._state.open_send_channels -= 1 - if self._state.open_send_channels == 0: - receive_events = list(self._state.waiting_receivers.keys()) - self._state.waiting_receivers.clear() - for event in receive_events: - event.set() - - async def aclose(self) -> None: - self.close() - - def statistics(self) -> MemoryObjectStreamStatistics: - """ - Return statistics about the current state of this stream. - - .. versionadded:: 3.0 - """ - return self._state.statistics() - - def __enter__(self) -> MemoryObjectSendStream[T_contra]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def __del__(self) -> None: - if not self._closed: - warnings.warn( - f"Unclosed <{self.__class__.__name__} at {id(self):x}>", - ResourceWarning, - stacklevel=1, - source=self, - ) diff --git a/venv/lib/python3.10/site-packages/anyio/streams/stapled.py b/venv/lib/python3.10/site-packages/anyio/streams/stapled.py deleted file mode 100644 index 9248b68abfbff90ddd64646fbe9cabb9f0ebe869..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/streams/stapled.py +++ /dev/null @@ -1,147 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "MultiListener", - "StapledByteStream", - "StapledObjectStream", -) - -from collections.abc import Callable, Mapping, Sequence -from dataclasses import dataclass -from typing import Any, Generic, TypeVar - -from ..abc import ( - ByteReceiveStream, - ByteSendStream, - ByteStream, - Listener, - ObjectReceiveStream, - ObjectSendStream, - ObjectStream, - TaskGroup, -) - -T_Item = TypeVar("T_Item") -T_Stream = TypeVar("T_Stream") - - -@dataclass(eq=False) -class StapledByteStream(ByteStream): - """ - Combines two byte streams into a single, bidirectional byte stream. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param ByteSendStream send_stream: the sending byte stream - :param ByteReceiveStream receive_stream: the receiving byte stream - """ - - send_stream: ByteSendStream - receive_stream: ByteReceiveStream - - async def receive(self, max_bytes: int = 65536) -> bytes: - return await self.receive_stream.receive(max_bytes) - - async def send(self, item: bytes) -> None: - await self.send_stream.send(item) - - async def send_eof(self) -> None: - await self.send_stream.aclose() - - async def aclose(self) -> None: - await self.send_stream.aclose() - await self.receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.send_stream.extra_attributes, - **self.receive_stream.extra_attributes, - } - - -@dataclass(eq=False) -class StapledObjectStream(Generic[T_Item], ObjectStream[T_Item]): - """ - Combines two object streams into a single, bidirectional object stream. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param ObjectSendStream send_stream: the sending object stream - :param ObjectReceiveStream receive_stream: the receiving object stream - """ - - send_stream: ObjectSendStream[T_Item] - receive_stream: ObjectReceiveStream[T_Item] - - async def receive(self) -> T_Item: - return await self.receive_stream.receive() - - async def send(self, item: T_Item) -> None: - await self.send_stream.send(item) - - async def send_eof(self) -> None: - await self.send_stream.aclose() - - async def aclose(self) -> None: - await self.send_stream.aclose() - await self.receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.send_stream.extra_attributes, - **self.receive_stream.extra_attributes, - } - - -@dataclass(eq=False) -class MultiListener(Generic[T_Stream], Listener[T_Stream]): - """ - Combines multiple listeners into one, serving connections from all of them at once. - - Any MultiListeners in the given collection of listeners will have their listeners - moved into this one. - - Extra attributes are provided from each listener, with each successive listener - overriding any conflicting attributes from the previous one. - - :param listeners: listeners to serve - :type listeners: Sequence[Listener[T_Stream]] - """ - - listeners: Sequence[Listener[T_Stream]] - - def __post_init__(self) -> None: - listeners: list[Listener[T_Stream]] = [] - for listener in self.listeners: - if isinstance(listener, MultiListener): - listeners.extend(listener.listeners) - del listener.listeners[:] # type: ignore[attr-defined] - else: - listeners.append(listener) - - self.listeners = listeners - - async def serve( - self, handler: Callable[[T_Stream], Any], task_group: TaskGroup | None = None - ) -> None: - from .. import create_task_group - - async with create_task_group() as tg: - for listener in self.listeners: - tg.start_soon(listener.serve, handler, task_group) - - async def aclose(self) -> None: - for listener in self.listeners: - await listener.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - attributes: dict = {} - for listener in self.listeners: - attributes.update(listener.extra_attributes) - - return attributes diff --git a/venv/lib/python3.10/site-packages/anyio/streams/text.py b/venv/lib/python3.10/site-packages/anyio/streams/text.py deleted file mode 100644 index 296cd250459f3848bb333301fff1ac32973f219a..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/streams/text.py +++ /dev/null @@ -1,176 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "TextConnectable", - "TextReceiveStream", - "TextSendStream", - "TextStream", -) - -import codecs -import sys -from collections.abc import Callable, Mapping -from dataclasses import InitVar, dataclass, field -from typing import Any - -from ..abc import ( - AnyByteReceiveStream, - AnyByteSendStream, - AnyByteStream, - AnyByteStreamConnectable, - ObjectReceiveStream, - ObjectSendStream, - ObjectStream, - ObjectStreamConnectable, -) - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - - -@dataclass(eq=False) -class TextReceiveStream(ObjectReceiveStream[str]): - """ - Stream wrapper that decodes bytes to strings using the given encoding. - - Decoding is done using :class:`~codecs.IncrementalDecoder` which returns any - completely received unicode characters as soon as they come in. - - :param transport_stream: any bytes-based receive stream - :param encoding: character encoding to use for decoding bytes to strings (defaults - to ``utf-8``) - :param errors: handling scheme for decoding errors (defaults to ``strict``; see the - `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteReceiveStream - encoding: InitVar[str] = "utf-8" - errors: InitVar[str] = "strict" - _decoder: codecs.IncrementalDecoder = field(init=False) - - def __post_init__(self, encoding: str, errors: str) -> None: - decoder_class = codecs.getincrementaldecoder(encoding) - self._decoder = decoder_class(errors=errors) - - async def receive(self) -> str: - while True: - chunk = await self.transport_stream.receive() - decoded = self._decoder.decode(chunk) - if decoded: - return decoded - - async def aclose(self) -> None: - await self.transport_stream.aclose() - self._decoder.reset() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.transport_stream.extra_attributes - - -@dataclass(eq=False) -class TextSendStream(ObjectSendStream[str]): - """ - Sends strings to the wrapped stream as bytes using the given encoding. - - :param AnyByteSendStream transport_stream: any bytes-based send stream - :param str encoding: character encoding to use for encoding strings to bytes - (defaults to ``utf-8``) - :param str errors: handling scheme for encoding errors (defaults to ``strict``; see - the `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteSendStream - encoding: InitVar[str] = "utf-8" - errors: str = "strict" - _encoder: Callable[..., tuple[bytes, int]] = field(init=False) - - def __post_init__(self, encoding: str) -> None: - self._encoder = codecs.getencoder(encoding) - - async def send(self, item: str) -> None: - encoded = self._encoder(item, self.errors)[0] - await self.transport_stream.send(encoded) - - async def aclose(self) -> None: - await self.transport_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.transport_stream.extra_attributes - - -@dataclass(eq=False) -class TextStream(ObjectStream[str]): - """ - A bidirectional stream that decodes bytes to strings on receive and encodes strings - to bytes on send. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param AnyByteStream transport_stream: any bytes-based stream - :param str encoding: character encoding to use for encoding/decoding strings to/from - bytes (defaults to ``utf-8``) - :param str errors: handling scheme for encoding errors (defaults to ``strict``; see - the `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteStream - encoding: InitVar[str] = "utf-8" - errors: InitVar[str] = "strict" - _receive_stream: TextReceiveStream = field(init=False) - _send_stream: TextSendStream = field(init=False) - - def __post_init__(self, encoding: str, errors: str) -> None: - self._receive_stream = TextReceiveStream( - self.transport_stream, encoding=encoding, errors=errors - ) - self._send_stream = TextSendStream( - self.transport_stream, encoding=encoding, errors=errors - ) - - async def receive(self) -> str: - return await self._receive_stream.receive() - - async def send(self, item: str) -> None: - await self._send_stream.send(item) - - async def send_eof(self) -> None: - await self.transport_stream.send_eof() - - async def aclose(self) -> None: - await self._send_stream.aclose() - await self._receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self._send_stream.extra_attributes, - **self._receive_stream.extra_attributes, - } - - -class TextConnectable(ObjectStreamConnectable[str]): - def __init__(self, connectable: AnyByteStreamConnectable): - """ - :param connectable: the bytestream endpoint to wrap - - """ - self.connectable = connectable - - @override - async def connect(self) -> TextStream: - stream = await self.connectable.connect() - return TextStream(stream) diff --git a/venv/lib/python3.10/site-packages/anyio/streams/tls.py b/venv/lib/python3.10/site-packages/anyio/streams/tls.py deleted file mode 100644 index b507488c57a3f90c64ea80733910dc9311e5a3e3..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/streams/tls.py +++ /dev/null @@ -1,424 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "TLSAttribute", - "TLSConnectable", - "TLSListener", - "TLSStream", -) - -import logging -import re -import ssl -import sys -from collections.abc import Callable, Mapping -from dataclasses import dataclass -from functools import wraps -from ssl import SSLContext -from typing import Any, TypeVar - -from .. import ( - BrokenResourceError, - EndOfStream, - aclose_forcefully, - get_cancelled_exc_class, - to_thread, -) -from .._core._typedattr import TypedAttributeSet, typed_attribute -from ..abc import ( - AnyByteStream, - AnyByteStreamConnectable, - ByteStream, - ByteStreamConnectable, - Listener, - TaskGroup, -) - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") -_PCTRTT: TypeAlias = tuple[tuple[str, str], ...] -_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] - - -class TLSAttribute(TypedAttributeSet): - """Contains Transport Layer Security related attributes.""" - - #: the selected ALPN protocol - alpn_protocol: str | None = typed_attribute() - #: the channel binding for type ``tls-unique`` - channel_binding_tls_unique: bytes = typed_attribute() - #: the selected cipher - cipher: tuple[str, str, int] = typed_attribute() - #: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert` - # for more information) - peer_certificate: None | (dict[str, str | _PCTRTTT | _PCTRTT]) = typed_attribute() - #: the peer certificate in binary form - peer_certificate_binary: bytes | None = typed_attribute() - #: ``True`` if this is the server side of the connection - server_side: bool = typed_attribute() - #: ciphers shared by the client during the TLS handshake (``None`` if this is the - #: client side) - shared_ciphers: list[tuple[str, str, int]] | None = typed_attribute() - #: the :class:`~ssl.SSLObject` used for encryption - ssl_object: ssl.SSLObject = typed_attribute() - #: ``True`` if this stream does (and expects) a closing TLS handshake when the - #: stream is being closed - standard_compatible: bool = typed_attribute() - #: the TLS protocol version (e.g. ``TLSv1.2``) - tls_version: str = typed_attribute() - - -@dataclass(eq=False) -class TLSStream(ByteStream): - """ - A stream wrapper that encrypts all sent data and decrypts received data. - - This class has no public initializer; use :meth:`wrap` instead. - All extra attributes from :class:`~TLSAttribute` are supported. - - :var AnyByteStream transport_stream: the wrapped stream - - """ - - transport_stream: AnyByteStream - standard_compatible: bool - _ssl_object: ssl.SSLObject - _read_bio: ssl.MemoryBIO - _write_bio: ssl.MemoryBIO - - @classmethod - async def wrap( - cls, - transport_stream: AnyByteStream, - *, - server_side: bool | None = None, - hostname: str | None = None, - ssl_context: ssl.SSLContext | None = None, - standard_compatible: bool = True, - ) -> TLSStream: - """ - Wrap an existing stream with Transport Layer Security. - - This performs a TLS handshake with the peer. - - :param transport_stream: a bytes-transporting stream to wrap - :param server_side: ``True`` if this is the server side of the connection, - ``False`` if this is the client side (if omitted, will be set to ``False`` - if ``hostname`` has been provided, ``False`` otherwise). Used only to create - a default context when an explicit context has not been provided. - :param hostname: host name of the peer (if host name checking is desired) - :param ssl_context: the SSLContext object to use (if not provided, a secure - default will be created) - :param standard_compatible: if ``False``, skip the closing handshake when - closing the connection, and don't raise an exception if the peer does the - same - :raises ~ssl.SSLError: if the TLS handshake fails - - """ - if server_side is None: - server_side = not hostname - - if not ssl_context: - purpose = ( - ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH - ) - ssl_context = ssl.create_default_context(purpose) - - # Re-enable detection of unexpected EOFs if it was disabled by Python - if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"): - ssl_context.options &= ~ssl.OP_IGNORE_UNEXPECTED_EOF - - bio_in = ssl.MemoryBIO() - bio_out = ssl.MemoryBIO() - - # External SSLContext implementations may do blocking I/O in wrap_bio(), - # but the standard library implementation won't - if type(ssl_context) is ssl.SSLContext: - ssl_object = ssl_context.wrap_bio( - bio_in, bio_out, server_side=server_side, server_hostname=hostname - ) - else: - ssl_object = await to_thread.run_sync( - ssl_context.wrap_bio, - bio_in, - bio_out, - server_side, - hostname, - None, - ) - - wrapper = cls( - transport_stream=transport_stream, - standard_compatible=standard_compatible, - _ssl_object=ssl_object, - _read_bio=bio_in, - _write_bio=bio_out, - ) - await wrapper._call_sslobject_method(ssl_object.do_handshake) - return wrapper - - async def _call_sslobject_method( - self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] - ) -> T_Retval: - while True: - try: - result = func(*args) - except ssl.SSLWantReadError: - try: - # Flush any pending writes first - if self._write_bio.pending: - await self.transport_stream.send(self._write_bio.read()) - - data = await self.transport_stream.receive() - except EndOfStream: - self._read_bio.write_eof() - except OSError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - raise BrokenResourceError from exc - else: - self._read_bio.write(data) - except ssl.SSLWantWriteError: - await self.transport_stream.send(self._write_bio.read()) - except ssl.SSLSyscallError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - raise BrokenResourceError from exc - except ssl.SSLError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - if isinstance(exc, ssl.SSLEOFError) or ( - exc.strerror and "UNEXPECTED_EOF_WHILE_READING" in exc.strerror - ): - if self.standard_compatible: - raise BrokenResourceError from exc - else: - raise EndOfStream from None - - raise - else: - # Flush any pending writes first - if self._write_bio.pending: - await self.transport_stream.send(self._write_bio.read()) - - return result - - async def unwrap(self) -> tuple[AnyByteStream, bytes]: - """ - Does the TLS closing handshake. - - :return: a tuple of (wrapped byte stream, bytes left in the read buffer) - - """ - await self._call_sslobject_method(self._ssl_object.unwrap) - self._read_bio.write_eof() - self._write_bio.write_eof() - return self.transport_stream, self._read_bio.read() - - async def aclose(self) -> None: - if self.standard_compatible: - try: - await self.unwrap() - except BaseException: - await aclose_forcefully(self.transport_stream) - raise - - await self.transport_stream.aclose() - - async def receive(self, max_bytes: int = 65536) -> bytes: - data = await self._call_sslobject_method(self._ssl_object.read, max_bytes) - if not data: - raise EndOfStream - - return data - - async def send(self, item: bytes) -> None: - await self._call_sslobject_method(self._ssl_object.write, item) - - async def send_eof(self) -> None: - tls_version = self.extra(TLSAttribute.tls_version) - match = re.match(r"TLSv(\d+)(?:\.(\d+))?", tls_version) - if match: - major, minor = int(match.group(1)), int(match.group(2) or 0) - if (major, minor) < (1, 3): - raise NotImplementedError( - f"send_eof() requires at least TLSv1.3; current " - f"session uses {tls_version}" - ) - - raise NotImplementedError( - "send_eof() has not yet been implemented for TLS streams" - ) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.transport_stream.extra_attributes, - TLSAttribute.alpn_protocol: self._ssl_object.selected_alpn_protocol, - TLSAttribute.channel_binding_tls_unique: ( - self._ssl_object.get_channel_binding - ), - TLSAttribute.cipher: self._ssl_object.cipher, - TLSAttribute.peer_certificate: lambda: self._ssl_object.getpeercert(False), - TLSAttribute.peer_certificate_binary: lambda: self._ssl_object.getpeercert( - True - ), - TLSAttribute.server_side: lambda: self._ssl_object.server_side, - TLSAttribute.shared_ciphers: lambda: self._ssl_object.shared_ciphers() - if self._ssl_object.server_side - else None, - TLSAttribute.standard_compatible: lambda: self.standard_compatible, - TLSAttribute.ssl_object: lambda: self._ssl_object, - TLSAttribute.tls_version: self._ssl_object.version, - } - - -@dataclass(eq=False) -class TLSListener(Listener[TLSStream]): - """ - A convenience listener that wraps another listener and auto-negotiates a TLS session - on every accepted connection. - - If the TLS handshake times out or raises an exception, - :meth:`handle_handshake_error` is called to do whatever post-mortem processing is - deemed necessary. - - Supports only the :attr:`~TLSAttribute.standard_compatible` extra attribute. - - :param Listener listener: the listener to wrap - :param ssl_context: the SSL context object - :param standard_compatible: a flag passed through to :meth:`TLSStream.wrap` - :param handshake_timeout: time limit for the TLS handshake - (passed to :func:`~anyio.fail_after`) - """ - - listener: Listener[Any] - ssl_context: ssl.SSLContext - standard_compatible: bool = True - handshake_timeout: float = 30 - - @staticmethod - async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None: - """ - Handle an exception raised during the TLS handshake. - - This method does 3 things: - - #. Forcefully closes the original stream - #. Logs the exception (unless it was a cancellation exception) using the - ``anyio.streams.tls`` logger - #. Reraises the exception if it was a base exception or a cancellation exception - - :param exc: the exception - :param stream: the original stream - - """ - await aclose_forcefully(stream) - - # Log all except cancellation exceptions - if not isinstance(exc, get_cancelled_exc_class()): - # CPython (as of 3.11.5) returns incorrect `sys.exc_info()` here when using - # any asyncio implementation, so we explicitly pass the exception to log - # (https://github.com/python/cpython/issues/108668). Trio does not have this - # issue because it works around the CPython bug. - logging.getLogger(__name__).exception( - "Error during TLS handshake", exc_info=exc - ) - - # Only reraise base exceptions and cancellation exceptions - if not isinstance(exc, Exception) or isinstance(exc, get_cancelled_exc_class()): - raise - - async def serve( - self, - handler: Callable[[TLSStream], Any], - task_group: TaskGroup | None = None, - ) -> None: - @wraps(handler) - async def handler_wrapper(stream: AnyByteStream) -> None: - from .. import fail_after - - try: - with fail_after(self.handshake_timeout): - wrapped_stream = await TLSStream.wrap( - stream, - ssl_context=self.ssl_context, - standard_compatible=self.standard_compatible, - ) - except BaseException as exc: - await self.handle_handshake_error(exc, stream) - else: - await handler(wrapped_stream) - - await self.listener.serve(handler_wrapper, task_group) - - async def aclose(self) -> None: - await self.listener.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - TLSAttribute.standard_compatible: lambda: self.standard_compatible, - } - - -class TLSConnectable(ByteStreamConnectable): - """ - Wraps another connectable and does TLS negotiation after a successful connection. - - :param connectable: the connectable to wrap - :param hostname: host name of the server (if host name checking is desired) - :param ssl_context: the SSLContext object to use (if not provided, a secure default - will be created) - :param standard_compatible: if ``False``, skip the closing handshake when closing - the connection, and don't raise an exception if the server does the same - """ - - def __init__( - self, - connectable: AnyByteStreamConnectable, - *, - hostname: str | None = None, - ssl_context: ssl.SSLContext | None = None, - standard_compatible: bool = True, - ) -> None: - self.connectable = connectable - self.ssl_context: SSLContext = ssl_context or ssl.create_default_context( - ssl.Purpose.SERVER_AUTH - ) - if not isinstance(self.ssl_context, ssl.SSLContext): - raise TypeError( - "ssl_context must be an instance of ssl.SSLContext, not " - f"{type(self.ssl_context).__name__}" - ) - self.hostname = hostname - self.standard_compatible = standard_compatible - - @override - async def connect(self) -> TLSStream: - stream = await self.connectable.connect() - try: - return await TLSStream.wrap( - stream, - hostname=self.hostname, - ssl_context=self.ssl_context, - standard_compatible=self.standard_compatible, - ) - except BaseException: - await aclose_forcefully(stream) - raise diff --git a/venv/lib/python3.10/site-packages/anyio/to_interpreter.py b/venv/lib/python3.10/site-packages/anyio/to_interpreter.py deleted file mode 100644 index 694dbe77bc8581032ee72316afe4e0590311ba00..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/to_interpreter.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "run_sync", - "current_default_interpreter_limiter", -) - -import atexit -import os -import sys -from collections import deque -from collections.abc import Callable -from typing import Any, Final, TypeVar - -from . import current_time, to_thread -from ._core._exceptions import BrokenWorkerInterpreter -from ._core._synchronization import CapacityLimiter -from .lowlevel import RunVar - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 14): - from concurrent.interpreters import ExecutionFailed, create - - def _interp_call( - func: Callable[..., Any], args: tuple[Any, ...] - ) -> tuple[Any, bool]: - try: - retval = func(*args) - except BaseException as exc: - return exc, True - else: - return retval, False - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - self._interpreter = create() - - def destroy(self) -> None: - self._interpreter.close() - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - try: - res, is_exception = self._interpreter.call(_interp_call, func, args) - except ExecutionFailed as exc: - raise BrokenWorkerInterpreter(exc.excinfo) from exc - - if is_exception: - raise res - - return res -elif sys.version_info >= (3, 13): - import _interpqueues - import _interpreters - - UNBOUND: Final = 2 # I have no clue how this works, but it was used in the stdlib - FMT_UNPICKLED: Final = 0 - FMT_PICKLED: Final = 1 - QUEUE_PICKLE_ARGS: Final = (FMT_PICKLED, UNBOUND) - QUEUE_UNPICKLE_ARGS: Final = (FMT_UNPICKLED, UNBOUND) - - _run_func = compile( - """ -import _interpqueues -from _interpreters import NotShareableError -from pickle import loads, dumps, HIGHEST_PROTOCOL - -QUEUE_PICKLE_ARGS = (1, 2) -QUEUE_UNPICKLE_ARGS = (0, 2) - -item = _interpqueues.get(queue_id)[0] -try: - func, args = loads(item) - retval = func(*args) -except BaseException as exc: - is_exception = True - retval = exc -else: - is_exception = False - -try: - _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_UNPICKLE_ARGS) -except NotShareableError: - retval = dumps(retval, HIGHEST_PROTOCOL) - _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_PICKLE_ARGS) - """, - "", - "exec", - ) - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - self._interpreter_id = _interpreters.create() - self._queue_id = _interpqueues.create(1, *QUEUE_UNPICKLE_ARGS) - _interpreters.set___main___attrs( - self._interpreter_id, {"queue_id": self._queue_id} - ) - - def destroy(self) -> None: - _interpqueues.destroy(self._queue_id) - _interpreters.destroy(self._interpreter_id) - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - import pickle - - item = pickle.dumps((func, args), pickle.HIGHEST_PROTOCOL) - _interpqueues.put(self._queue_id, item, *QUEUE_PICKLE_ARGS) - exc_info = _interpreters.exec(self._interpreter_id, _run_func) - if exc_info: - raise BrokenWorkerInterpreter(exc_info) - - res = _interpqueues.get(self._queue_id) - (res, is_exception), fmt = res[:2] - if fmt == FMT_PICKLED: - res = pickle.loads(res) - - if is_exception: - raise res - - return res -else: - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - raise RuntimeError("subinterpreters require at least Python 3.13") - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - raise NotImplementedError - - def destroy(self) -> None: - pass - - -DEFAULT_CPU_COUNT: Final = 8 # this is just an arbitrarily selected value -MAX_WORKER_IDLE_TIME = ( - 30 # seconds a subinterpreter can be idle before becoming eligible for pruning -) - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -_idle_workers = RunVar[deque[_Worker]]("_available_workers") -_default_interpreter_limiter = RunVar[CapacityLimiter]("_default_interpreter_limiter") - - -def _stop_workers(workers: deque[_Worker]) -> None: - for worker in workers: - worker.destroy() - - workers.clear() - - -async def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a subinterpreter. - - .. warning:: On Python 3.13, the :mod:`concurrent.interpreters` module was not yet - available, so the code path for that Python version relies on an undocumented, - private API. As such, it is recommended to not rely on this function for anything - mission-critical on Python 3.13. - - :param func: a callable - :param args: the positional arguments for the callable - :param limiter: capacity limiter to use to limit the total number of subinterpreters - running (if omitted, the default limiter is used) - :return: the result of the call - :raises BrokenWorkerInterpreter: if there's an internal error in a subinterpreter - - """ - if limiter is None: - limiter = current_default_interpreter_limiter() - - try: - idle_workers = _idle_workers.get() - except LookupError: - idle_workers = deque() - _idle_workers.set(idle_workers) - atexit.register(_stop_workers, idle_workers) - - async with limiter: - try: - worker = idle_workers.pop() - except IndexError: - worker = _Worker() - - try: - return await to_thread.run_sync( - worker.call, - func, - args, - limiter=limiter, - ) - finally: - # Prune workers that have been idle for too long - now = current_time() - while idle_workers: - if now - idle_workers[0].last_used <= MAX_WORKER_IDLE_TIME: - break - - await to_thread.run_sync(idle_workers.popleft().destroy, limiter=limiter) - - worker.last_used = current_time() - idle_workers.append(worker) - - -def current_default_interpreter_limiter() -> CapacityLimiter: - """ - Return the capacity limiter used by default to limit the number of concurrently - running subinterpreters. - - Defaults to the number of CPU cores. - - :return: a capacity limiter object - - """ - try: - return _default_interpreter_limiter.get() - except LookupError: - limiter = CapacityLimiter(os.cpu_count() or DEFAULT_CPU_COUNT) - _default_interpreter_limiter.set(limiter) - return limiter diff --git a/venv/lib/python3.10/site-packages/anyio/to_process.py b/venv/lib/python3.10/site-packages/anyio/to_process.py deleted file mode 100644 index b289234ecfaafc1651dfa76e924291e5a5e9521e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/to_process.py +++ /dev/null @@ -1,266 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "current_default_process_limiter", - "process_worker", - "run_sync", -) - -import os -import pickle -import subprocess -import sys -from collections import deque -from collections.abc import Callable -from importlib.util import module_from_spec, spec_from_file_location -from typing import TypeVar, cast - -from ._core._eventloop import current_time, get_async_backend, get_cancelled_exc_class -from ._core._exceptions import BrokenWorkerProcess -from ._core._subprocesses import open_process -from ._core._synchronization import CapacityLimiter -from ._core._tasks import CancelScope, fail_after -from .abc import ByteReceiveStream, ByteSendStream, Process -from .lowlevel import RunVar, checkpoint_if_cancelled -from .streams.buffered import BufferedByteReceiveStream - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -WORKER_MAX_IDLE_TIME = 300 # 5 minutes - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -_process_pool_workers: RunVar[set[Process]] = RunVar("_process_pool_workers") -_process_pool_idle_workers: RunVar[deque[tuple[Process, float]]] = RunVar( - "_process_pool_idle_workers" -) -_default_process_limiter: RunVar[CapacityLimiter] = RunVar("_default_process_limiter") - - -async def run_sync( # type: ignore[return] - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - cancellable: bool = False, - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a worker process. - - If the ``cancellable`` option is enabled and the task waiting for its completion is - cancelled, the worker process running it will be abruptly terminated using SIGKILL - (or ``terminateProcess()`` on Windows). - - :param func: a callable - :param args: positional arguments for the callable - :param cancellable: ``True`` to allow cancellation of the operation while it's - running - :param limiter: capacity limiter to use to limit the total amount of processes - running (if omitted, the default limiter is used) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - :return: an awaitable that yields the return value of the function. - - """ - - async def send_raw_command(pickled_cmd: bytes) -> object: - try: - await stdin.send(pickled_cmd) - response = await buffered.receive_until(b"\n", 50) - status, length = response.split(b" ") - if status not in (b"RETURN", b"EXCEPTION"): - raise RuntimeError( - f"Worker process returned unexpected response: {response!r}" - ) - - pickled_response = await buffered.receive_exactly(int(length)) - except BaseException as exc: - workers.discard(process) - try: - process.kill() - with CancelScope(shield=True): - await process.aclose() - except ProcessLookupError: - pass - - if isinstance(exc, get_cancelled_exc_class()): - raise - else: - raise BrokenWorkerProcess from exc - - retval = pickle.loads(pickled_response) - if status == b"EXCEPTION": - assert isinstance(retval, BaseException) - raise retval - else: - return retval - - # First pickle the request before trying to reserve a worker process - await checkpoint_if_cancelled() - request = pickle.dumps(("run", func, args), protocol=pickle.HIGHEST_PROTOCOL) - - # If this is the first run in this event loop thread, set up the necessary variables - try: - workers = _process_pool_workers.get() - idle_workers = _process_pool_idle_workers.get() - except LookupError: - workers = set() - idle_workers = deque() - _process_pool_workers.set(workers) - _process_pool_idle_workers.set(idle_workers) - get_async_backend().setup_process_pool_exit_at_shutdown(workers) - - async with limiter or current_default_process_limiter(): - # Pop processes from the pool (starting from the most recently used) until we - # find one that hasn't exited yet - process: Process - while idle_workers: - process, idle_since = idle_workers.pop() - if process.returncode is None: - stdin = cast(ByteSendStream, process.stdin) - buffered = BufferedByteReceiveStream( - cast(ByteReceiveStream, process.stdout) - ) - - # Prune any other workers that have been idle for WORKER_MAX_IDLE_TIME - # seconds or longer - now = current_time() - killed_processes: list[Process] = [] - while idle_workers: - if now - idle_workers[0][1] < WORKER_MAX_IDLE_TIME: - break - - process_to_kill, idle_since = idle_workers.popleft() - process_to_kill.kill() - workers.remove(process_to_kill) - killed_processes.append(process_to_kill) - - with CancelScope(shield=True): - for killed_process in killed_processes: - await killed_process.aclose() - - break - - workers.remove(process) - else: - command = [sys.executable, "-u", "-m", __name__] - process = await open_process( - command, stdin=subprocess.PIPE, stdout=subprocess.PIPE - ) - try: - stdin = cast(ByteSendStream, process.stdin) - buffered = BufferedByteReceiveStream( - cast(ByteReceiveStream, process.stdout) - ) - with fail_after(20): - message = await buffered.receive(6) - - if message != b"READY\n": - raise BrokenWorkerProcess( - f"Worker process returned unexpected response: {message!r}" - ) - - main_module_path = getattr(sys.modules["__main__"], "__file__", None) - pickled = pickle.dumps( - ("init", sys.path, main_module_path), - protocol=pickle.HIGHEST_PROTOCOL, - ) - await send_raw_command(pickled) - except (BrokenWorkerProcess, get_cancelled_exc_class()): - raise - except BaseException as exc: - process.kill() - raise BrokenWorkerProcess( - "Error during worker process initialization" - ) from exc - - workers.add(process) - - with CancelScope(shield=not cancellable): - try: - return cast(T_Retval, await send_raw_command(request)) - finally: - if process in workers: - idle_workers.append((process, current_time())) - - -def current_default_process_limiter() -> CapacityLimiter: - """ - Return the capacity limiter that is used by default to limit the number of worker - processes. - - :return: a capacity limiter object - - """ - try: - return _default_process_limiter.get() - except LookupError: - limiter = CapacityLimiter(os.cpu_count() or 2) - _default_process_limiter.set(limiter) - return limiter - - -def process_worker() -> None: - # Redirect standard streams to os.devnull so that user code won't interfere with the - # parent-worker communication - stdin = sys.stdin - stdout = sys.stdout - sys.stdin = open(os.devnull) - sys.stdout = open(os.devnull, "w") - - stdout.buffer.write(b"READY\n") - while True: - retval = exception = None - try: - command, *args = pickle.load(stdin.buffer) - except EOFError: - return - except BaseException as exc: - exception = exc - else: - if command == "run": - func, args = args - try: - retval = func(*args) - except BaseException as exc: - exception = exc - elif command == "init": - main_module_path: str | None - sys.path, main_module_path = args - del sys.modules["__main__"] - if main_module_path and os.path.isfile(main_module_path): - # Load the parent's main module but as __mp_main__ instead of - # __main__ (like multiprocessing does) to avoid infinite recursion - try: - spec = spec_from_file_location("__mp_main__", main_module_path) - if spec and spec.loader: - main = module_from_spec(spec) - spec.loader.exec_module(main) - sys.modules["__main__"] = main - except BaseException as exc: - exception = exc - try: - if exception is not None: - status = b"EXCEPTION" - pickled = pickle.dumps(exception, pickle.HIGHEST_PROTOCOL) - else: - status = b"RETURN" - pickled = pickle.dumps(retval, pickle.HIGHEST_PROTOCOL) - except BaseException as exc: - exception = exc - status = b"EXCEPTION" - pickled = pickle.dumps(exc, pickle.HIGHEST_PROTOCOL) - - stdout.buffer.write(b"%s %d\n" % (status, len(pickled))) - stdout.buffer.write(pickled) - - # Respect SIGTERM - if isinstance(exception, SystemExit): - raise exception - - -if __name__ == "__main__": - process_worker() diff --git a/venv/lib/python3.10/site-packages/anyio/to_thread.py b/venv/lib/python3.10/site-packages/anyio/to_thread.py deleted file mode 100644 index 4be5b7190ad9142a1aeb684bff0bd40245f71fb6..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/anyio/to_thread.py +++ /dev/null @@ -1,78 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "run_sync", - "current_default_thread_limiter", -) - -import sys -from collections.abc import Callable -from typing import TypeVar -from warnings import warn - -from ._core._eventloop import get_async_backend -from .abc import CapacityLimiter - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - - -async def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - abandon_on_cancel: bool = False, - cancellable: bool | None = None, - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a worker thread. - - If the ``cancellable`` option is enabled and the task waiting for its completion is - cancelled, the thread will still run its course but its return value (or any raised - exception) will be ignored. - - :param func: a callable - :param args: positional arguments for the callable - :param abandon_on_cancel: ``True`` to abandon the thread (leaving it to run - unchecked on own) if the host task is cancelled, ``False`` to ignore - cancellations in the host task until the operation has completed in the worker - thread - :param cancellable: deprecated alias of ``abandon_on_cancel``; will override - ``abandon_on_cancel`` if both parameters are passed - :param limiter: capacity limiter to use to limit the total amount of threads running - (if omitted, the default limiter is used) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - :return: an awaitable that yields the return value of the function. - - """ - if cancellable is not None: - abandon_on_cancel = cancellable - warn( - "The `cancellable=` keyword argument to `anyio.to_thread.run_sync` is " - "deprecated since AnyIO 4.1.0; use `abandon_on_cancel=` instead", - DeprecationWarning, - stacklevel=2, - ) - - return await get_async_backend().run_sync_in_worker_thread( - func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter - ) - - -def current_default_thread_limiter() -> CapacityLimiter: - """ - Return the capacity limiter that is used by default to limit the number of - concurrent threads. - - :return: a capacity limiter object - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_default_thread_limiter() diff --git a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/METADATA b/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/METADATA deleted file mode 100644 index 73df8c84d445126cbef97c279b70a046c2c63c53..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/METADATA +++ /dev/null @@ -1,78 +0,0 @@ -Metadata-Version: 2.4 -Name: certifi -Version: 2026.2.25 -Summary: Python package for providing Mozilla's CA Bundle. -Home-page: https://github.com/certifi/python-certifi -Author: Kenneth Reitz -Author-email: me@kennethreitz.com -License: MPL-2.0 -Project-URL: Source, https://github.com/certifi/python-certifi -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Requires-Python: >=3.7 -License-File: LICENSE -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: license-file -Dynamic: project-url -Dynamic: requires-python -Dynamic: summary - -Certifi: Python SSL Certificates -================================ - -Certifi provides Mozilla's carefully curated collection of Root Certificates for -validating the trustworthiness of SSL certificates while verifying the identity -of TLS hosts. It has been extracted from the `Requests`_ project. - -Installation ------------- - -``certifi`` is available on PyPI. Simply install it with ``pip``:: - - $ pip install certifi - -Usage ------ - -To reference the installed certificate authority (CA) bundle, you can use the -built-in function:: - - >>> import certifi - - >>> certifi.where() - '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' - -Or from the command line:: - - $ python -m certifi - /usr/local/lib/python3.7/site-packages/certifi/cacert.pem - -Enjoy! - -.. _`Requests`: https://requests.readthedocs.io/en/master/ - -Addition/Removal of Certificates --------------------------------- - -Certifi does not support any addition/removal or other modification of the -CA trust store content. This project is intended to provide a reliable and -highly portable root of trust to python deployments. Look to upstream projects -for methods to use alternate trust. diff --git a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/RECORD b/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/RECORD deleted file mode 100644 index dcdcb27beb9e28e452ab1dd28be1365d65f261cd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/RECORD +++ /dev/null @@ -1,14 +0,0 @@ -certifi-2026.2.25.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -certifi-2026.2.25.dist-info/METADATA,sha256=4NMuGXdg_hBiRA3paKVXYcDmE3VXEBWxTvCL2xlDyPU,2474 -certifi-2026.2.25.dist-info/RECORD,, -certifi-2026.2.25.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91 -certifi-2026.2.25.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 -certifi-2026.2.25.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 -certifi/__init__.py,sha256=c9eaYufv1pSLl0Q8QNcMiMLLH4WquDcxdPyKjmI4opY,94 -certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 -certifi/__pycache__/__init__.cpython-310.pyc,, -certifi/__pycache__/__main__.cpython-310.pyc,, -certifi/__pycache__/core.cpython-310.pyc,, -certifi/cacert.pem,sha256=_JFloSQDJj5-v72te-ej6sD6XTJdPHBGXyjTaQByyig,272441 -certifi/core.py,sha256=XFXycndG5pf37ayeF8N32HUuDafsyhkVMbO4BAPWHa0,3394 -certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/WHEEL b/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/WHEEL deleted file mode 100644 index 1ef5583317a5e59140e3f1c85c2db91aec0961e8..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (82.0.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/licenses/LICENSE deleted file mode 100644 index 62b076cdee58ec8f34034141ba0befd9015b0c7e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/licenses/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -This package contains a modified version of ca-bundle.crt: - -ca-bundle.crt -- Bundle of CA Root Certificates - -This is a bundle of X.509 certificates of public Certificate Authorities -(CA). These were automatically extracted from Mozilla's root certificates -file (certdata.txt). This file can be found in the mozilla source tree: -https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt -It contains the certificates in PEM format and therefore -can be directly used with curl / libcurl / php_curl, or with -an Apache+mod_ssl webserver for SSL client authentication. -Just configure this file as the SSLCACertificateFile.# - -***** BEGIN LICENSE BLOCK ***** -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain -one at http://mozilla.org/MPL/2.0/. - -***** END LICENSE BLOCK ***** -@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/top_level.txt b/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/top_level.txt deleted file mode 100644 index 963eac530b9bc28d704d1bc410299c68e3216d4d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi-2026.2.25.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -certifi diff --git a/venv/lib/python3.10/site-packages/certifi/__init__.py b/venv/lib/python3.10/site-packages/certifi/__init__.py deleted file mode 100644 index 16c0c7c268f3d28336595254df687d2f5f48b574..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .core import contents, where - -__all__ = ["contents", "where"] -__version__ = "2026.02.25" diff --git a/venv/lib/python3.10/site-packages/certifi/__main__.py b/venv/lib/python3.10/site-packages/certifi/__main__.py deleted file mode 100644 index 8945b5da857f4a7dec2b84f1225f012f6098418c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi/__main__.py +++ /dev/null @@ -1,12 +0,0 @@ -import argparse - -from certifi import contents, where - -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--contents", action="store_true") -args = parser.parse_args() - -if args.contents: - print(contents()) -else: - print(where()) diff --git a/venv/lib/python3.10/site-packages/certifi/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/certifi/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index d4d505ee7510c8043015975698ce5e1434e4fc63..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/certifi/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/certifi/__pycache__/__main__.cpython-310.pyc b/venv/lib/python3.10/site-packages/certifi/__pycache__/__main__.cpython-310.pyc deleted file mode 100644 index 78c53b113582f33cb3b2ebad63dd7c5ae99951e5..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/certifi/__pycache__/__main__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/certifi/__pycache__/core.cpython-310.pyc b/venv/lib/python3.10/site-packages/certifi/__pycache__/core.cpython-310.pyc deleted file mode 100644 index 1290ecc66c8a1db224d601f4bbcbafb36960a647..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/certifi/__pycache__/core.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/certifi/cacert.pem b/venv/lib/python3.10/site-packages/certifi/cacert.pem deleted file mode 100644 index 5ec1afe02d4d859082d132cf74f4c56954e3d6be..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi/cacert.pem +++ /dev/null @@ -1,4494 +0,0 @@ - -# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2" -# Serial: 1289 -# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b -# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 -# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3" -# Serial: 1478 -# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf -# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 -# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root CA" -# Serial: 17154717934120587862167794914071425081 -# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 -# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 -# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root CA" -# Serial: 10944719598952040374951832963794454346 -# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e -# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 -# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert High Assurance EV Root CA" -# Serial: 3553400076410547919724730734378100087 -# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a -# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 -# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- - -# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Label: "SwissSign Gold CA - G2" -# Serial: 13492815561806991280 -# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 -# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 -# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln -biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF -MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT -d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 -76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ -bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c -6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE -emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd -MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt -MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y -MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y -FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi -aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM -gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB -qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 -lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn -8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 -45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO -UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 -O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC -bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv -GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a -77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC -hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 -92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp -Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w -ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt -Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- - -# Issuer: CN=SecureTrust CA O=SecureTrust Corporation -# Subject: CN=SecureTrust CA O=SecureTrust Corporation -# Label: "SecureTrust CA" -# Serial: 17199774589125277788362757014266862032 -# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 -# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 -# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- - -# Issuer: CN=Secure Global CA O=SecureTrust Corporation -# Subject: CN=Secure Global CA O=SecureTrust Corporation -# Label: "Secure Global CA" -# Serial: 9751836167731051554232119481456978597 -# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de -# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b -# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- - -# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO Certification Authority O=COMODO CA Limited -# Label: "COMODO Certification Authority" -# Serial: 104350513648249232941998508985834464573 -# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 -# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b -# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB -gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV -BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw -MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl -YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P -RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 -UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI -2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 -Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp -+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ -DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O -nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW -/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g -PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u -QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY -SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv -IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 -zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd -BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB -ZQ== ------END CERTIFICATE----- - -# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Label: "COMODO ECC Certification Authority" -# Serial: 41578283867086692638256921589707938090 -# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 -# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 -# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT -IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw -MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy -ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N -T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR -FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J -cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW -BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm -fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv -GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- - -# Issuer: CN=Certigna O=Dhimyotis -# Subject: CN=Certigna O=Dhimyotis -# Label: "Certigna" -# Serial: 18364802974209362175 -# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff -# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 -# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV -BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X -DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ -BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 -QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny -gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw -zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q -130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 -JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw -ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT -AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj -AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG -9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h -bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc -fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu -HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w -t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- - -# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Label: "ePKI Root Certification Authority" -# Serial: 28956088682735189655030529057352760477 -# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 -# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 -# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- - -# Issuer: O=certSIGN OU=certSIGN ROOT CA -# Subject: O=certSIGN OU=certSIGN ROOT CA -# Label: "certSIGN ROOT CA" -# Serial: 35210227249154 -# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 -# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b -# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT -AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD -QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP -MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do -0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ -UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d -RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ -OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv -JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C -AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O -BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ -LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY -MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ -44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I -Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw -i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN -9u6wWk5JRFRYX0KD ------END CERTIFICATE----- - -# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" -# Serial: 80544274841616 -# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 -# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 -# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- - -# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Label: "Microsec e-Szigno Root CA 2009" -# Serial: 14014712776195784473 -# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 -# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e -# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G -CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y -OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx -FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp -Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP -kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc -cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U -fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 -N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC -xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 -+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM -Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG -SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h -mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk -ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c -2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t -HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Label: "GlobalSign Root CA - R3" -# Serial: 4835703278459759426209954 -# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 -# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad -# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- - -# Issuer: CN=Izenpe.com O=IZENPE S.A. -# Subject: CN=Izenpe.com O=IZENPE S.A. -# Label: "Izenpe.com" -# Serial: 917563065490389241595536686991402621 -# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 -# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 -# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 -MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 -ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD -VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j -b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq -scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO -xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H -LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX -uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD -yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ -JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q -rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN -BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L -hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB -QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ -HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu -Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg -QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB -BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA -A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb -laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 -awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo -JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw -LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT -VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk -LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb -UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ -QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ -naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls -QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- - -# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Label: "Go Daddy Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 -# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b -# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 -# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e -# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Services Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 -# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f -# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs -ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD -VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy -ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy -dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p -OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 -8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K -Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe -hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk -6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q -AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI -bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB -ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z -qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn -0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN -sSi6 ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA" -# Serial: 279744 -# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 -# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e -# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- - -# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Label: "TWCA Root Certification Authority" -# Serial: 1 -# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 -# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 -# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES -MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU -V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz -WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO -LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE -AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH -K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX -RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z -rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx -3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq -hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC -MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls -XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D -lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn -aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ -YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- - -# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Label: "Security Communication RootCA2" -# Serial: 0 -# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 -# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 -# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX -DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy -dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj -YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV -OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr -zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM -VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ -hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO -ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw -awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs -OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF -coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc -okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 -t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy -1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ -SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- - -# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Label: "Actalis Authentication Root CA" -# Serial: 6271844772424770508 -# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 -# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac -# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE -BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w -MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC -SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 -ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv -UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX -4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 -KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ -gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb -rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ -51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F -be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe -KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F -v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn -fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 -jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz -ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL -e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 -jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz -WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V -SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j -pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX -X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok -fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R -K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU -ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU -LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT -LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 2 Root CA" -# Serial: 2 -# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 -# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 -# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr -6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV -L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 -1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx -MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ -QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB -arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr -Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi -FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS -P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN -9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz -uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h -9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t -OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo -+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 -KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 -DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us -H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ -I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 -5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h -3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz -Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 3 Root CA" -# Serial: 2 -# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec -# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 -# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y -ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E -N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 -tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX -0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c -/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X -KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY -zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS -O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D -34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP -K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv -Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj -QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS -IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 -HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa -O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv -033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u -dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE -kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 -3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD -u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq -4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 3" -# Serial: 1 -# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef -# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 -# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN -8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ -RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 -hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 -ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM -EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 -A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy -WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ -1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 -6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT -91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p -TpPDpFQUWw== ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 2009" -# Serial: 623603 -# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f -# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 -# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha -ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM -HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 -UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 -tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R -ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM -lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp -/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G -A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy -MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl -cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js -L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL -BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni -acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K -zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 -PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y -Johw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 EV 2009" -# Serial: 623604 -# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 -# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 -# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw -NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV -BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn -ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 -3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z -qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR -p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 -HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw -ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea -HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw -Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh -c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E -RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt -dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku -Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp -3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF -CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na -xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX -KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 ------END CERTIFICATE----- - -# Issuer: CN=CA Disig Root R2 O=Disig a.s. -# Subject: CN=CA Disig Root R2 O=Disig a.s. -# Label: "CA Disig Root R2" -# Serial: 10572350602393338211 -# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 -# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 -# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV -BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu -MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy -MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx -EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe -NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH -PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I -x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe -QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR -yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO -QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 -H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ -QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD -i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs -nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 -rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI -hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf -GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb -lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka -+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal -TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i -nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 -gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr -G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os -zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x -L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- - -# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Label: "ACCVRAIZ1" -# Serial: 6828503384748696800 -# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 -# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 -# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 ------BEGIN CERTIFICATE----- -MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE -AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw -CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ -BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND -VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb -qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY -HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo -G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA -lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr -IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ -0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH -k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO -m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa -cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl -uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI -KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls -ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG -AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 -VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT -VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG -CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA -cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA -QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA -7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA -cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA -QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA -czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu -aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt -aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud -DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp -D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU -JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m -AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD -vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms -tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH -7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h -I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA -h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF -d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H -pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 ------END CERTIFICATE----- - -# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA Global Root CA" -# Serial: 3262 -# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 -# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 -# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx -EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT -VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 -NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT -B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF -10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz -0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh -MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH -zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc -46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 -yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi -laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP -oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA -BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE -qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm -4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL -1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn -LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF -H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo -RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ -nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh -15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW -6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW -nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j -wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz -aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy -KwbQBM0= ------END CERTIFICATE----- - -# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Label: "TeliaSonera Root CA v1" -# Serial: 199041966741090107964904287217786801558 -# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c -# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 -# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 ------BEGIN CERTIFICATE----- -MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw -NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv -b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD -VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F -VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 -7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X -Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ -/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs -81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm -dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe -Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu -sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 -pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs -slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ -arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD -VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG -9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl -dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx -0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj -TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed -Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 -Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI -OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 -vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW -t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn -HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx -SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 2" -# Serial: 1 -# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a -# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 -# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd -AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC -FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi -1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq -jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ -wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ -WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy -NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC -uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw -IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 -g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN -9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP -BSeOE6Fuwg== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot 2011 O=Atos -# Subject: CN=Atos TrustedRoot 2011 O=Atos -# Label: "Atos TrustedRoot 2011" -# Serial: 6643877497813316402 -# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 -# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 -# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE -AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG -EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM -FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC -REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp -Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM -VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ -SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ -4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L -cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi -eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG -A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 -DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j -vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP -DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc -maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D -lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv -KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 1 G3" -# Serial: 687049649626669250736271037606554624078720034195 -# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab -# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 -# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 -MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV -wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe -rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 -68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh -4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp -UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o -abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc -3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G -KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt -hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO -Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt -zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD -ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 -cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN -qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 -YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv -b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 -8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k -NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj -ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp -q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt -nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2 G3" -# Serial: 390156079458959257446133169266079962026824725800 -# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 -# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 -# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 -MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf -qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW -n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym -c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ -O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 -o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j -IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq -IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz -8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh -vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l -7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG -cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD -ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC -roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga -W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n -lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE -+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV -csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd -dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg -KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM -HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 -WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3 G3" -# Serial: 268090761170461462463995952157327242137089239581 -# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 -# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d -# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 -MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR -/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu -FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR -U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c -ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR -FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k -A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw -eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl -sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp -VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q -A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ -ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD -ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI -FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv -oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg -u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP -0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf -3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl -8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ -DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN -PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ -ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G2" -# Serial: 15385348160840213938643033620894905419 -# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d -# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f -# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 ------BEGIN CERTIFICATE----- -MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA -n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc -biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp -EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA -bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu -YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW -BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI -QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I -0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni -lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 -B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv -ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo -IhNzbM8m9Yop5w== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G3" -# Serial: 15459312981008553731928384953135426796 -# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb -# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 -# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 ------BEGIN CERTIFICATE----- -MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg -RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf -Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q -RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD -AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY -JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv -6pZjamVFkpUBtA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G2" -# Serial: 4293743540046975378534879503202253541 -# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 -# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 -# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G3" -# Serial: 7089244469030293291760083333884364146 -# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca -# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e -# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe -Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw -EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x -IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG -fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO -Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx -AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ -oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 -sycX ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Trusted Root G4" -# Serial: 7451500558977370777930084869016614236 -# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 -# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 -# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 ------BEGIN CERTIFICATE----- -MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg -RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y -ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If -xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV -ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO -DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ -jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ -CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi -EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM -fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY -uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK -chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t -9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD -ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 -SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd -+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc -fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa -sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N -cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N -0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie -4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI -r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 -/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm -gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ ------END CERTIFICATE----- - -# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Label: "COMODO RSA Certification Authority" -# Serial: 101909084537582093308941363524873193117 -# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 -# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 -# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 ------BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR -6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X -pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC -9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV -/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf -Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z -+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w -qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah -SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC -u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf -Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq -crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl -wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM -4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV -2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna -FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ -CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK -boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke -jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL -S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb -QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl -0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB -NVOFBkpdn627G190 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Label: "USERTrust RSA Certification Authority" -# Serial: 2645093764781058787591871645665788717 -# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 -# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e -# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw -MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV -BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B -3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY -tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ -Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 -VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT -79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 -c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT -Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l -c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee -UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE -Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF -Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO -VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 -ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs -8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR -iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze -Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ -XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ -qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB -VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB -L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG -jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Label: "USERTrust ECC Certification Authority" -# Serial: 123013823720199481456569720443997572134 -# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 -# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 -# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a ------BEGIN CERTIFICATE----- -MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl -eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT -JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT -Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg -VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo -I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng -o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G -A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB -zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW -RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Label: "GlobalSign ECC Root CA - R5" -# Serial: 32785792099990507226680698011560947931244 -# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 -# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa -# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 ------BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc -8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke -hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI -KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg -515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO -xwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Label: "IdenTrust Commercial Root CA 1" -# Serial: 13298821034946342390520003877796839426 -# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 -# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 -# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu -VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw -MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw -JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT -3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU -+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp -S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 -bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi -T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL -vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK -Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK -dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT -c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv -l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N -iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD -ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH -6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt -LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 -nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 -+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK -W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT -AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq -l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG -4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ -mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A -7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Label: "IdenTrust Public Sector Root CA 1" -# Serial: 13298821034946342390521976156843933698 -# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba -# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd -# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu -VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN -MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 -MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 -ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy -RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS -bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF -/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R -3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw -EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy -9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V -GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ -2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV -WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD -W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN -AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj -t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV -DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 -TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G -lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW -mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df -WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 -+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ -tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA -GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv -8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE----- - -# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority -# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority -# Label: "CFCA EV ROOT" -# Serial: 407555286 -# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 -# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 -# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD -TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx -MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j -aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP -T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 -sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL -TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 -/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp -7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz -EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt -hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP -a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot -aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg -TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV -PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv -cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL -tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd -BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB -ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT -ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL -jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS -ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy -P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 -xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d -Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN -5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe -/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z -AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ -5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GB CA" -# Serial: 157768595616588414422159278966750757568 -# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d -# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed -# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt -MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg -Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i -YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x -CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG -b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh -bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 -HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx -WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX -1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk -u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P -99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r -M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB -BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh -cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 -gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO -ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf -aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic -Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE----- - -# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Label: "SZAFIR ROOT CA2" -# Serial: 357043034767186914217277344587386743377558296292 -# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 -# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de -# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 -ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw -NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L -cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg -Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN -QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT -3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw -3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 -3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 -BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN -XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF -AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw -8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG -nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP -oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy -d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg -LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA 2" -# Serial: 44979900017204383099463764357512596969 -# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 -# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 -# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB -gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG -A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz -OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ -VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 -b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA -DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn -0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB -OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE -fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E -Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m -o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i -sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW -OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez -Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS -adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n -3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ -F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf -CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 -XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm -djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ -WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb -AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq -P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko -b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj -XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P -5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi -DrW5viSP ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce -# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 -# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 ------BEGIN CERTIFICATE----- -MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix -DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k -IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT -N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v -dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG -A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh -ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx -QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA -4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 -AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 -4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C -ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV -9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD -gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 -Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq -NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko -LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc -Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd -ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I -XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI -M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot -9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V -Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea -j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh -X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ -l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf -bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 -pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK -e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 -vm9qp/UsQu0yrbYhnr68 ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef -# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 -# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 ------BEGIN CERTIFICATE----- -MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN -BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl -bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv -b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ -BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj -YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 -MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 -dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg -QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa -jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi -C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep -lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof -TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X1 O=Internet Security Research Group -# Subject: CN=ISRG Root X1 O=Internet Security Research Group -# Label: "ISRG Root X1" -# Serial: 172886928669790476064670243504169061120 -# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e -# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 -# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- - -# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Label: "AC RAIZ FNMT-RCM" -# Serial: 485876308206448804701554682760554759 -# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d -# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 -# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx -CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ -WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ -BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG -Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ -yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf -BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz -WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF -tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z -374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC -IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL -mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 -wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS -MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 -ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet -UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H -YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 -LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD -nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 -RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM -LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf -77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N -JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm -fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp -6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp -1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B -9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok -RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv -uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 1 O=Amazon -# Subject: CN=Amazon Root CA 1 O=Amazon -# Label: "Amazon Root CA 1" -# Serial: 143266978916655856878034712317230054538369994 -# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 -# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 -# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e ------BEGIN CERTIFICATE----- -MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj -ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM -9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw -IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 -VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L -93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm -jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA -A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI -U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs -N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv -o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU -5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy -rqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 2 O=Amazon -# Subject: CN=Amazon Root CA 2 O=Amazon -# Label: "Amazon Root CA 2" -# Serial: 143266982885963551818349160658925006970653239 -# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 -# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a -# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK -gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ -W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg -1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K -8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r -2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me -z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR -8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj -mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz -7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 -+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI -0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm -UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 -LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY -+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS -k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl -7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm -btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl -urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ -fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 -n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE -76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H -9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT -4PsJYGw= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 3 O=Amazon -# Subject: CN=Amazon Root CA 3 O=Amazon -# Label: "Amazon Root CA 3" -# Serial: 143266986699090766294700635381230934788665930 -# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 -# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e -# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 ------BEGIN CERTIFICATE----- -MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl -ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr -ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr -BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM -YyRIHN8wfdVoOw== ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 4 O=Amazon -# Subject: CN=Amazon Root CA 4 O=Amazon -# Label: "Amazon Root CA 4" -# Serial: 143266989758080763974105200630763877849284878 -# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd -# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be -# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 ------BEGIN CERTIFICATE----- -MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi -9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk -M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB -MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw -CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW -1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE----- - -# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" -# Serial: 1 -# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 -# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca -# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 ------BEGIN CERTIFICATE----- -MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx -GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp -bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w -KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 -BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy -dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG -EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll -IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU -QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT -TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg -LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 -a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr -LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr -N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X -YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ -iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f -AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH -V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh -AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf -IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 -lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c -8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf -lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE----- - -# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Label: "GDCA TrustAUTH R5 ROOT" -# Serial: 9009899650740120186 -# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 -# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 -# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 ------BEGIN CERTIFICATE----- -MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE -BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ -IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 -MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w -HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj -Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj -TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u -KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj -qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm -MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 -ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP -zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk -L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC -jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA -HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC -AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg -p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm -DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 -COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry -L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf -JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg -IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io -2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV -09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ -XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq -T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe -MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Label: "SSL.com Root Certification Authority RSA" -# Serial: 8875640296558310041 -# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 -# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb -# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE -BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK -DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz -OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv -bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R -xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX -qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC -C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 -6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh -/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF -YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E -JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc -US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 -ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm -+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi -M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G -A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV -cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc -Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs -PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ -q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 -cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr -a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I -H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y -K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu -nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf -oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY -Ic2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com Root Certification Authority ECC" -# Serial: 8495723813297216424 -# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e -# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a -# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 ------BEGIN CERTIFICATE----- -MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz -WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 -b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS -b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI -7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg -CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud -EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD -VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T -kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ -gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority RSA R2" -# Serial: 6248227494352943350 -# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 -# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a -# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c ------BEGIN CERTIFICATE----- -MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV -BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE -CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy -MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G -A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD -DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq -M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf -OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa -4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 -HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR -aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA -b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ -Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV -PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO -pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu -UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY -MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV -HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 -9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW -s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 -Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg -cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM -79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz -/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt -ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm -Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK -QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ -w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi -S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 -mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority ECC" -# Serial: 3182246526754555285 -# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 -# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d -# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 ------BEGIN CERTIFICATE----- -MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx -NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv -bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA -VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku -WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX -5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ -ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg -h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Label: "GlobalSign Root CA - R6" -# Serial: 1417766617973444989252670301619537 -# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae -# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 -# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg -MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx -MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET -MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI -xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k -ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD -aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw -LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw -1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX -k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 -SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h -bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n -WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY -rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce -MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu -bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN -nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt -Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 -55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj -vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf -cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz -oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp -nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs -pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v -JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R -8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 -5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GC CA" -# Serial: 44084345621038548146064804565436152554 -# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 -# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 -# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d ------BEGIN CERTIFICATE----- -MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw -CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 -bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg -Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ -BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu -ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS -b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni -eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W -p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T -rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV -57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg -Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE----- - -# Issuer: CN=UCA Global G2 Root O=UniTrust -# Subject: CN=UCA Global G2 Root O=UniTrust -# Label: "UCA Global G2 Root" -# Serial: 124779693093741543919145257850076631279 -# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 -# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a -# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH -bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x -CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds -b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr -b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 -kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm -VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R -VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc -C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj -tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY -D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv -j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl -NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 -iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP -O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV -ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj -L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 -1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl -1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU -b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV -PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj -y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb -EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg -DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI -+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy -YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX -UB+K+wb1whnw0A== ------END CERTIFICATE----- - -# Issuer: CN=UCA Extended Validation Root O=UniTrust -# Subject: CN=UCA Extended Validation Root O=UniTrust -# Label: "UCA Extended Validation Root" -# Serial: 106100277556486529736699587978573607008 -# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 -# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a -# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF -eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx -MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV -BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog -D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS -sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop -O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk -sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi -c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj -VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz -KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ -TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G -sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs -1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD -fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN -l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR -ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ -VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 -c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp -4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s -t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj -2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO -vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C -xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx -cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM -fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax ------END CERTIFICATE----- - -# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Label: "Certigna Root CA" -# Serial: 269714418870597844693661054334862075617 -# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 -# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 -# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 ------BEGIN CERTIFICATE----- -MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw -WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw -MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x -MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD -VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX -BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO -ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M -CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu -I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm -TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh -C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf -ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz -IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT -Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k -JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 -hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB -GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of -1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov -L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo -dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr -aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq -hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L -6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG -HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 -0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB -lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi -o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 -gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v -faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 -Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh -jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw -3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign Root CA - G1" -# Serial: 235931866688319308814040 -# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac -# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c -# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD -VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU -ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH -MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO -MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv -Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz -f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO -8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq -d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM -tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt -Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB -o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x -PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM -wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d -GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH -6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby -RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx -iN66zB+Afko= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign ECC Root CA - G3" -# Serial: 287880440101571086945156 -# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 -# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 -# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b ------BEGIN CERTIFICATE----- -MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG -EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo -bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g -RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ -TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s -b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 -WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS -fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB -zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq -hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB -CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD -+JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Label: "emSign Root CA - C1" -# Serial: 825510296613316004955058 -# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 -# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 -# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG -A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg -SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v -dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ -BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ -HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH -3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH -GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c -xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 -aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq -TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 -/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 -kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG -YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT -+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo -WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Label: "emSign ECC Root CA - C3" -# Serial: 582948710642506000014504 -# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 -# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 -# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 ------BEGIN CERTIFICATE----- -MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG -EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx -IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND -IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci -MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti -sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O -BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB -Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c -3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J -0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Label: "Hongkong Post Root CA 3" -# Serial: 46170865288971385588281144162979347873371282084 -# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 -# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 -# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 ------BEGIN CERTIFICATE----- -MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL -BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ -SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n -a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 -NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT -CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u -Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO -dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI -VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV -9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY -2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY -vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt -bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb -x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ -l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK -TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj -Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e -i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw -DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG -7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk -MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr -gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk -GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS -3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm -Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ -l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c -JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP -L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa -LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG -mpv0 ------END CERTIFICATE----- - -# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft ECC Root Certificate Authority 2017" -# Serial: 136839042543790627607696632466672567020 -# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 -# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 -# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 ------BEGIN CERTIFICATE----- -MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD -VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw -MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV -UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy -b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR -ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb -hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 -FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV -L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB -iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE----- - -# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft RSA Root Certificate Authority 2017" -# Serial: 40975477897264996090493496164228220339 -# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 -# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 -# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 ------BEGIN CERTIFICATE----- -MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw -NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG -EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N -aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ -Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 -ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 -HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm -gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ -jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc -aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG -YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 -W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K -UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH -+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q -W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC -LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC -gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 -tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh -SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 -TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 -pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR -xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp -GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 -dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN -AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB -RA+GsCyRxj3qrg+E ------END CERTIFICATE----- - -# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Label: "e-Szigno Root CA 2017" -# Serial: 411379200276854331539784714 -# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 -# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 -# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 ------BEGIN CERTIFICATE----- -MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV -BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk -LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv -b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ -BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg -THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v -IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv -xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H -Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB -eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo -jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ -+efcMQ== ------END CERTIFICATE----- - -# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Label: "certSIGN Root CA G2" -# Serial: 313609486401300475190 -# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 -# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 -# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV -BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g -Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ -BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ -R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF -dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw -vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ -uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp -n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs -cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW -xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P -rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF -DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx -DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy -LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C -eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ -d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq -kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC -b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl -qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 -OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c -NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk -ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO -pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj -03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk -PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE -1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX -QRBdJ3NghVdJIgc= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global Certification Authority" -# Serial: 1846098327275375458322922162 -# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e -# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 -# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 ------BEGIN CERTIFICATE----- -MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw -CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x -ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 -c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx -OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI -SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI -b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn -swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu -7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 -1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW -80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP -JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l -RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw -hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 -coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc -BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n -twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud -DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W -0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe -uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q -lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB -aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE -sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT -MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe -qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh -VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 -h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 -EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK -yeC2nOnOcXHebD8WpHk= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P256 Certification Authority" -# Serial: 4151900041497450638097112925 -# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 -# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf -# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 ------BEGIN CERTIFICATE----- -MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG -SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN -FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w -DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw -CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh -DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P384 Certification Authority" -# Serial: 2704997926503831671788816187 -# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 -# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 -# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 ------BEGIN CERTIFICATE----- -MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB -BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ -j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF -1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G -A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 -AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC -MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu -Sw== ------END CERTIFICATE----- - -# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Label: "NAVER Global Root Certification Authority" -# Serial: 9013692873798656336226253319739695165984492813 -# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b -# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 -# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 ------BEGIN CERTIFICATE----- -MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM -BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG -T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx -CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD -b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA -iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH -38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE -HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz -kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP -szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq -vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf -nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG -YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo -0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a -CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K -AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I -36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN -qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj -cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm -+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL -hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe -lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 -p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 -piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR -LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX -5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO -dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul -9XXeifdy ------END CERTIFICATE----- - -# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" -# Serial: 131542671362353147877283741781055151509 -# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb -# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a -# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb ------BEGIN CERTIFICATE----- -MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw -CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw -FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S -Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 -MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL -DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS -QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH -sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK -Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu -SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC -MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy -v+c= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Label: "GlobalSign Root R46" -# Serial: 1552617688466950547958867513931858518042577 -# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef -# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 -# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA -MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD -VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy -MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt -c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ -OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG -vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud -316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo -0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE -y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF -zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE -+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN -I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs -x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa -ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC -4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 -7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg -JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti -2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk -pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF -FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt -rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk -ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 -u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP -4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 -N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 -vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Label: "GlobalSign Root E46" -# Serial: 1552617690338932563915843282459653771421763 -# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f -# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 -# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 ------BEGIN CERTIFICATE----- -MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx -CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD -ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw -MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex -HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq -R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd -yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ -7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 -+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE----- - -# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Label: "ANF Secure Server Root CA" -# Serial: 996390341000653745 -# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 -# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 -# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 ------BEGIN CERTIFICATE----- -MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV -BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk -YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV -BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN -MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF -UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD -VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v -dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj -cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q -yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH -2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX -H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL -zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR -p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz -W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ -SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn -LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 -n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B -u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj -o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L -9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej -rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK -pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 -vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq -OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ -/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 -2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI -+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 -MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo -tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= ------END CERTIFICATE----- - -# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum EC-384 CA" -# Serial: 160250656287871593594747141429395092468 -# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 -# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed -# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw -CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw -JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT -EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 -WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT -LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX -BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE -KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm -Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 -EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J -UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn -nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Root CA" -# Serial: 40870380103424195783807378461123655149 -# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 -# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 -# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 -MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu -MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV -BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw -MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg -U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ -n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q -p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq -NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF -8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 -HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa -mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi -7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF -ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P -qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ -v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 -Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 -vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD -ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 -WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo -zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR -5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ -GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf -5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq -0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D -P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM -qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP -0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf -E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb ------END CERTIFICATE----- - -# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique -# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique -# Label: "TunTrust Root CA" -# Serial: 108534058042236574382096126452369648152337120275 -# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4 -# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb -# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41 ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL -BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg -Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv -b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG -EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u -IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ -n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd -2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF -VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ -GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF -li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU -r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 -eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb -MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg -jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB -7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW -5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE -ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 -90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z -xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu -QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 -FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH -22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP -xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn -dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 -Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b -nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ -CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH -u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj -d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= ------END CERTIFICATE----- - -# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Label: "HARICA TLS RSA Root CA 2021" -# Serial: 76817823531813593706434026085292783742 -# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91 -# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d -# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs -MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg -Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL -MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl -YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv -b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l -mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE -4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv -a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M -pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw -Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b -LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY -AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB -AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq -E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr -W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ -CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU -X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 -f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja -H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP -JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P -zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt -jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 -/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT -BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 -aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW -xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU -63ZTGI0RmLo= ------END CERTIFICATE----- - -# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Label: "HARICA TLS ECC Root CA 2021" -# Serial: 137515985548005187474074462014555733966 -# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 -# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 -# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 ------BEGIN CERTIFICATE----- -MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw -CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh -cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v -dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG -A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj -aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg -Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 -KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y -STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD -AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw -SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN -nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps ------END CERTIFICATE----- - -# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" -# Serial: 1977337328857672817 -# MD5 Fingerprint: 4e:6e:9b:54:4c:ca:b7:fa:48:e4:90:b1:15:4b:1c:a3 -# SHA1 Fingerprint: 0b:be:c2:27:22:49:cb:39:aa:db:35:5c:53:e3:8c:ae:78:ff:b6:fe -# SHA256 Fingerprint: 57:de:05:83:ef:d2:b2:6e:03:61:da:99:da:9d:f4:64:8d:ef:7e:e8:44:1c:3b:72:8a:fa:9b:cd:e0:f9:b2:6a ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 -MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc -tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd -IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j -b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC -AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw -ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m -iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF -Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ -hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P -Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE -EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV -1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t -CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR -5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw -f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 -ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK -GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV ------END CERTIFICATE----- - -# Issuer: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. -# Subject: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. -# Label: "vTrus ECC Root CA" -# Serial: 630369271402956006249506845124680065938238527194 -# MD5 Fingerprint: de:4b:c1:f5:52:8c:9b:43:e1:3e:8f:55:54:17:8d:85 -# SHA1 Fingerprint: f6:9c:db:b0:fc:f6:02:13:b6:52:32:a6:a3:91:3f:16:70:da:c3:e1 -# SHA256 Fingerprint: 30:fb:ba:2c:32:23:8e:2a:98:54:7a:f9:79:31:e5:50:42:8b:9b:3f:1c:8e:eb:66:33:dc:fa:86:c5:b2:7d:d3 ------BEGIN CERTIFICATE----- -MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw -RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY -BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz -MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u -LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 -v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd -e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw -V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA -AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG -GJTO ------END CERTIFICATE----- - -# Issuer: CN=vTrus Root CA O=iTrusChina Co.,Ltd. -# Subject: CN=vTrus Root CA O=iTrusChina Co.,Ltd. -# Label: "vTrus Root CA" -# Serial: 387574501246983434957692974888460947164905180485 -# MD5 Fingerprint: b8:c9:37:df:fa:6b:31:84:64:c5:ea:11:6a:1b:75:fc -# SHA1 Fingerprint: 84:1a:69:fb:f5:cd:1a:25:34:13:3d:e3:f8:fc:b8:99:d0:c9:14:b7 -# SHA256 Fingerprint: 8a:71:de:65:59:33:6f:42:6c:26:e5:38:80:d0:0d:88:a1:8d:a4:c6:a9:1f:0d:cb:61:94:e2:06:c5:c9:63:87 ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL -BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x -FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx -MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s -THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc -IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU -AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ -GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 -8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH -flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt -J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim -0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN -pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ -UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW -OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB -AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet -8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd -nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j -bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM -Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv -TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS -S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr -I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 -b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB -UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P -Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven -sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X2 O=Internet Security Research Group -# Subject: CN=ISRG Root X2 O=Internet Security Research Group -# Label: "ISRG Root X2" -# Serial: 87493402998870891108772069816698636114 -# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 -# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af -# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg -R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 -MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT -ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW -+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 -ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI -zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW -tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 -/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- - -# Issuer: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. -# Subject: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. -# Label: "HiPKI Root CA - G1" -# Serial: 60966262342023497858655262305426234976 -# MD5 Fingerprint: 69:45:df:16:65:4b:e8:68:9a:8f:76:5f:ff:80:9e:d3 -# SHA1 Fingerprint: 6a:92:e4:a8:ee:1b:ec:96:45:37:e3:29:57:49:cd:96:e3:e5:d2:60 -# SHA256 Fingerprint: f0:15:ce:3c:c2:39:bf:ef:06:4b:e9:f1:d2:c4:17:e1:a0:26:4a:0a:94:be:1f:0c:8d:12:18:64:eb:69:49:cc ------BEGIN CERTIFICATE----- -MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa -Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 -YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw -qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv -Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 -lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz -Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ -KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK -FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj -HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr -y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ -/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM -a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 -fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG -SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi -7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc -SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza -ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc -XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg -iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho -L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF -Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr -kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ -vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU -YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Label: "GlobalSign ECC Root CA - R4" -# Serial: 159662223612894884239637590694 -# MD5 Fingerprint: 26:29:f8:6d:e1:88:bf:a2:65:7f:aa:c4:cd:0f:7f:fc -# SHA1 Fingerprint: 6b:a0:b0:98:e1:71:ef:5a:ad:fe:48:15:80:77:10:f4:bd:6f:0b:28 -# SHA256 Fingerprint: b0:85:d7:0b:96:4f:19:1a:73:e4:af:0d:54:ae:7a:0e:07:aa:fd:af:9b:71:dd:08:62:13:8a:b7:32:5a:24:a2 ------BEGIN CERTIFICATE----- -MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD -VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw -MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g -UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT -BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx -uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV -HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ -+wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 -bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R1 O=Google Trust Services LLC -# Subject: CN=GTS Root R1 O=Google Trust Services LLC -# Label: "GTS Root R1" -# Serial: 159662320309726417404178440727 -# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 -# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a -# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo -27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w -Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw -TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl -qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH -szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 -Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk -MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 -wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p -aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN -VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb -C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe -QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy -h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 -7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J -ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef -MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ -Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT -6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ -0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm -2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb -bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R2 O=Google Trust Services LLC -# Subject: CN=GTS Root R2 O=Google Trust Services LLC -# Label: "GTS Root R2" -# Serial: 159662449406622349769042896298 -# MD5 Fingerprint: 1e:39:c0:53:e6:1e:29:82:0b:ca:52:55:36:5d:57:dc -# SHA1 Fingerprint: 9a:44:49:76:32:db:de:fa:d0:bc:fb:5a:7b:17:bd:9e:56:09:24:94 -# SHA256 Fingerprint: 8d:25:cd:97:22:9d:bf:70:35:6b:da:4e:b3:cc:73:40:31:e2:4c:f0:0f:af:cf:d3:2d:c7:6e:b5:84:1c:7e:a8 ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt -nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY -6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu -MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k -RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg -f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV -+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo -dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW -Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa -G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq -gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H -vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 -0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC -B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u -NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg -yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev -HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 -xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR -TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg -JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV -7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl -6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R3 O=Google Trust Services LLC -# Subject: CN=GTS Root R3 O=Google Trust Services LLC -# Label: "GTS Root R3" -# Serial: 159662495401136852707857743206 -# MD5 Fingerprint: 3e:e7:9d:58:02:94:46:51:94:e5:e0:22:4a:8b:e7:73 -# SHA1 Fingerprint: ed:e5:71:80:2b:c8:92:b9:5b:83:3c:d2:32:68:3f:09:cd:a0:1e:46 -# SHA256 Fingerprint: 34:d8:a7:3e:e2:08:d9:bc:db:0d:95:65:20:93:4b:4e:40:e6:94:82:59:6e:8b:6f:73:c8:42:6b:01:0a:6f:48 ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G -jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 -4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 -VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm -ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R4 O=Google Trust Services LLC -# Subject: CN=GTS Root R4 O=Google Trust Services LLC -# Label: "GTS Root R4" -# Serial: 159662532700760215368942768210 -# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 -# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 -# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi -QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR -HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D -9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 -p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD ------END CERTIFICATE----- - -# Issuer: CN=Telia Root CA v2 O=Telia Finland Oyj -# Subject: CN=Telia Root CA v2 O=Telia Finland Oyj -# Label: "Telia Root CA v2" -# Serial: 7288924052977061235122729490515358 -# MD5 Fingerprint: 0e:8f:ac:aa:82:df:85:b1:f4:dc:10:1c:fc:99:d9:48 -# SHA1 Fingerprint: b9:99:cd:d1:73:50:8a:c4:47:05:08:9c:8c:88:fb:be:a0:2b:40:cd -# SHA256 Fingerprint: 24:2b:69:74:2f:cb:1e:5b:2a:bf:98:89:8b:94:57:21:87:54:4e:5b:4d:99:11:78:65:73:62:1f:6a:74:b8:2c ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx -CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE -AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 -NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ -MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq -AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 -vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 -lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD -n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT -7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o -6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC -TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 -WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R -DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI -pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj -YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy -rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ -8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi -0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM -A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS -SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K -TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF -6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er -3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt -Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT -VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW -ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA -rBPuUBQemMc= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH -# Subject: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH -# Label: "D-TRUST BR Root CA 1 2020" -# Serial: 165870826978392376648679885835942448534 -# MD5 Fingerprint: b5:aa:4b:d5:ed:f7:e3:55:2e:8f:72:0a:f3:75:b8:ed -# SHA1 Fingerprint: 1f:5b:98:f0:e3:b5:f7:74:3c:ed:e6:b0:36:7d:32:cd:f4:09:41:67 -# SHA256 Fingerprint: e5:9a:aa:81:60:09:c2:2b:ff:5b:25:ba:d3:7d:f3:06:f0:49:79:7c:1f:81:d8:5a:b0:89:e6:57:bd:8f:00:44 ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 -NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS -zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 -QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ -VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW -wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV -dWNbFJWcHwHP2NVypw87 ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH -# Subject: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH -# Label: "D-TRUST EV Root CA 1 2020" -# Serial: 126288379621884218666039612629459926992 -# MD5 Fingerprint: 8c:2d:9d:70:9f:48:99:11:06:11:fb:e9:cb:30:c0:6e -# SHA1 Fingerprint: 61:db:8c:21:59:69:03:90:d8:7c:9c:12:86:54:cf:9d:3d:f4:dd:07 -# SHA256 Fingerprint: 08:17:0d:1a:a3:64:53:90:1a:2f:95:92:45:e3:47:db:0c:8d:37:ab:aa:bc:56:b8:1a:a1:00:dc:95:89:70:db ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 -NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC -/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD -wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 -OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA -y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb -gfM0agPnIjhQW+0ZT0MW ------END CERTIFICATE----- - -# Issuer: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. -# Subject: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. -# Label: "DigiCert TLS ECC P384 Root G5" -# Serial: 13129116028163249804115411775095713523 -# MD5 Fingerprint: d3:71:04:6a:43:1c:db:a6:59:e1:a8:a3:aa:c5:71:ed -# SHA1 Fingerprint: 17:f3:de:5e:9f:0f:19:e9:8e:f6:1f:32:26:6e:20:c4:07:ae:30:ee -# SHA256 Fingerprint: 01:8e:13:f0:77:25:32:cf:80:9b:d1:b1:72:81:86:72:83:fc:48:c6:e1:3b:e9:c6:98:12:85:4a:49:0c:1b:05 ------BEGIN CERTIFICATE----- -MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp -Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 -MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ -bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS -7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp -0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS -B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 -BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ -LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 -DXZDjC5Ty3zfDBeWUA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. -# Subject: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. -# Label: "DigiCert TLS RSA4096 Root G5" -# Serial: 11930366277458970227240571539258396554 -# MD5 Fingerprint: ac:fe:f7:34:96:a9:f2:b3:b4:12:4b:e4:27:41:6f:e1 -# SHA1 Fingerprint: a7:88:49:dc:5d:7c:75:8c:8c:de:39:98:56:b3:aa:d0:b2:a5:71:35 -# SHA256 Fingerprint: 37:1a:00:dc:05:33:b3:72:1a:7e:eb:40:e8:41:9e:70:79:9d:2b:0a:0f:2c:1d:80:69:31:65:f7:ce:c4:ad:75 ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT -HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN -NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs -IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ -ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 -2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp -wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM -pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD -nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po -sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx -Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd -Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX -KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe -XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL -tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv -TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw -GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H -PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF -O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ -REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik -AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv -/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ -p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw -MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF -qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK -ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ ------END CERTIFICATE----- - -# Issuer: CN=Certainly Root R1 O=Certainly -# Subject: CN=Certainly Root R1 O=Certainly -# Label: "Certainly Root R1" -# Serial: 188833316161142517227353805653483829216 -# MD5 Fingerprint: 07:70:d4:3e:82:87:a0:fa:33:36:13:f4:fa:33:e7:12 -# SHA1 Fingerprint: a0:50:ee:0f:28:71:f4:27:b2:12:6d:6f:50:96:25:ba:cc:86:42:af -# SHA256 Fingerprint: 77:b8:2c:d8:64:4c:43:05:f7:ac:c5:cb:15:6b:45:67:50:04:03:3d:51:c6:0c:62:02:a8:e0:c3:34:67:d3:a0 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw -PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy -dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 -YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 -1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT -vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed -aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 -1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 -r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 -cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ -wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ -6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA -2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH -Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR -eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB -/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u -d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr -PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d -8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi -1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd -rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di -taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 -lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj -yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn -Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy -yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n -wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 -OV+KmalBWQewLK8= ------END CERTIFICATE----- - -# Issuer: CN=Certainly Root E1 O=Certainly -# Subject: CN=Certainly Root E1 O=Certainly -# Label: "Certainly Root E1" -# Serial: 8168531406727139161245376702891150584 -# MD5 Fingerprint: 0a:9e:ca:cd:3e:52:50:c6:36:f3:4b:a3:ed:a7:53:e9 -# SHA1 Fingerprint: f9:e1:6d:dc:01:89:cf:d5:82:45:63:3e:c5:37:7d:c2:eb:93:6f:2b -# SHA256 Fingerprint: b4:58:5f:22:e4:ac:75:6a:4e:86:12:a1:36:1c:5d:9d:03:1a:93:fd:84:fe:bb:77:8f:a3:06:8b:0f:c4:2d:c2 ------BEGIN CERTIFICATE----- -MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw -CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu -bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ -BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s -eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK -+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 -QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 -hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm -ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG -BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR ------END CERTIFICATE----- - -# Issuer: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. -# Subject: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. -# Label: "Security Communication ECC RootCA1" -# Serial: 15446673492073852651 -# MD5 Fingerprint: 7e:43:b0:92:68:ec:05:43:4c:98:ab:5d:35:2e:7e:86 -# SHA1 Fingerprint: b8:0e:26:a9:bf:d2:b2:3b:c0:ef:46:c9:ba:c7:bb:f6:1d:0d:41:41 -# SHA256 Fingerprint: e7:4f:bd:a5:5b:d5:64:c4:73:a3:6b:44:1a:a7:99:c8:a6:8e:07:74:40:e8:28:8b:9f:a1:e5:0e:4b:ba:ca:11 ------BEGIN CERTIFICATE----- -MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT -AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD -VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx -NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT -HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 -IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl -dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK -ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu -9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O -be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= ------END CERTIFICATE----- - -# Issuer: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY -# Subject: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY -# Label: "BJCA Global Root CA1" -# Serial: 113562791157148395269083148143378328608 -# MD5 Fingerprint: 42:32:99:76:43:33:36:24:35:07:82:9b:28:f9:d0:90 -# SHA1 Fingerprint: d5:ec:8d:7b:4c:ba:79:f4:e7:e8:cb:9d:6b:ae:77:83:10:03:21:6a -# SHA256 Fingerprint: f3:89:6f:88:fe:7c:0a:88:27:66:a7:fa:6a:d2:74:9f:b5:7a:7f:3e:98:fb:76:9c:1f:a7:b0:9c:2c:44:d5:ae ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU -MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI -T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz -MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF -SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh -bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z -xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ -spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5 -58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR -at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll -5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq -nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK -V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/ -pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO -z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn -jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+ -WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF -7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 -YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli -awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u -+2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88 -X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN -SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo -P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI -+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz -znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9 -eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2 -YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy -r/6zcCwupvI= ------END CERTIFICATE----- - -# Issuer: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY -# Subject: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY -# Label: "BJCA Global Root CA2" -# Serial: 58605626836079930195615843123109055211 -# MD5 Fingerprint: 5e:0a:f6:47:5f:a6:14:e8:11:01:95:3f:4d:01:eb:3c -# SHA1 Fingerprint: f4:27:86:eb:6e:b8:6d:88:31:67:02:fb:ba:66:a4:53:00:aa:7a:a6 -# SHA256 Fingerprint: 57:4d:f6:93:1e:27:80:39:66:7b:72:0a:fd:c1:60:0f:c2:7e:b6:6d:d3:09:29:79:fb:73:85:64:87:21:28:82 ------BEGIN CERTIFICATE----- -MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw -CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ -VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy -MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ -TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS -b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B -IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+ -+kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK -sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA -94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B -43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== ------END CERTIFICATE----- - -# Issuer: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited -# Subject: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited -# Label: "Sectigo Public Server Authentication Root E46" -# Serial: 88989738453351742415770396670917916916 -# MD5 Fingerprint: 28:23:f8:b2:98:5c:37:16:3b:3e:46:13:4e:b0:b3:01 -# SHA1 Fingerprint: ec:8a:39:6c:40:f0:2e:bc:42:75:d4:9f:ab:1c:1a:5b:67:be:d2:9a -# SHA256 Fingerprint: c9:0f:26:f0:fb:1b:40:18:b2:22:27:51:9b:5c:a2:b5:3e:2c:a5:b3:be:5c:f1:8e:fe:1b:ef:47:38:0c:53:83 ------BEGIN CERTIFICATE----- -MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw -CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T -ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN -MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG -A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT -ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC -WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ -6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B -Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa -qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q -4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== ------END CERTIFICATE----- - -# Issuer: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited -# Subject: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited -# Label: "Sectigo Public Server Authentication Root R46" -# Serial: 156256931880233212765902055439220583700 -# MD5 Fingerprint: 32:10:09:52:00:d5:7e:6c:43:df:15:c0:b1:16:93:e5 -# SHA1 Fingerprint: ad:98:f9:f3:e4:7d:75:3b:65:d4:82:b3:a4:52:17:bb:6e:f5:e4:38 -# SHA256 Fingerprint: 7b:b6:47:a6:2a:ee:ac:88:bf:25:7a:a5:22:d0:1f:fe:a3:95:e0:ab:45:c7:3f:93:f6:56:54:ec:38:f2:5a:06 ------BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf -MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD -Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw -HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY -MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp -YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa -ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz -SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf -iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X -ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 -IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS -VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE -SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu -+Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt -8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L -HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt -zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P -AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c -mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ -YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 -gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA -Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB -JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX -DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui -TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 -dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 -LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp -0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY -QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL ------END CERTIFICATE----- - -# Issuer: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation -# Subject: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation -# Label: "SSL.com TLS RSA Root CA 2022" -# Serial: 148535279242832292258835760425842727825 -# MD5 Fingerprint: d8:4e:c6:59:30:d8:fe:a0:d6:7a:5a:2c:2c:69:78:da -# SHA1 Fingerprint: ec:2c:83:40:72:af:26:95:10:ff:0e:f2:03:ee:31:70:f6:78:9d:ca -# SHA256 Fingerprint: 8f:af:7d:2e:2c:b4:70:9b:b8:e0:b3:36:66:bf:75:a5:dd:45:b5:de:48:0f:8e:a8:d4:bf:e6:be:bc:17:f2:ed ------BEGIN CERTIFICATE----- -MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO -MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD -DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX -DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw -b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC -AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP -L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY -t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins -S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 -PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO -L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 -R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w -dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS -+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS -d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG -AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f -gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j -BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z -NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt -hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM -QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf -R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ -DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW -P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy -lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq -bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w -AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q -r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji -Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU -98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation -# Subject: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation -# Label: "SSL.com TLS ECC Root CA 2022" -# Serial: 26605119622390491762507526719404364228 -# MD5 Fingerprint: 99:d7:5c:f1:51:36:cc:e9:ce:d9:19:2e:77:71:56:c5 -# SHA1 Fingerprint: 9f:5f:d9:1a:54:6d:f5:0c:71:f0:ee:7a:bd:17:49:98:84:73:e2:39 -# SHA256 Fingerprint: c3:2f:fd:9f:46:f9:36:d1:6c:36:73:99:09:59:43:4b:9a:d6:0a:af:bb:9e:7c:f3:36:54:f1:44:cc:1b:a1:43 ------BEGIN CERTIFICATE----- -MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT -U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 -MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh -dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm -acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN -SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME -GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW -uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp -15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN -b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos -# Subject: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos -# Label: "Atos TrustedRoot Root CA ECC TLS 2021" -# Serial: 81873346711060652204712539181482831616 -# MD5 Fingerprint: 16:9f:ad:f1:70:ad:79:d6:ed:29:b4:d1:c5:79:70:a8 -# SHA1 Fingerprint: 9e:bc:75:10:42:b3:02:f3:81:f4:f7:30:62:d4:8f:c3:a7:51:b2:dd -# SHA256 Fingerprint: b2:fa:e5:3e:14:cc:d7:ab:92:12:06:47:01:ae:27:9c:1d:89:88:fa:cb:77:5f:a8:a0:08:91:4e:66:39:88:a8 ------BEGIN CERTIFICATE----- -MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w -LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w -CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 -MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF -Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI -zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X -tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 -AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 -KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD -aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu -CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo -9H1/IISpQuQo ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos -# Subject: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos -# Label: "Atos TrustedRoot Root CA RSA TLS 2021" -# Serial: 111436099570196163832749341232207667876 -# MD5 Fingerprint: d4:d3:46:b8:9a:c0:9c:76:5d:9e:3a:c3:b9:99:31:d2 -# SHA1 Fingerprint: 18:52:3b:0d:06:37:e4:d6:3a:df:23:e4:98:fb:5b:16:fb:86:74:48 -# SHA256 Fingerprint: 81:a9:08:8e:a5:9f:b3:64:c5:48:a6:f8:55:59:09:9b:6f:04:05:ef:bf:18:e5:32:4e:c9:f4:57:ba:00:11:2f ------BEGIN CERTIFICATE----- -MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM -MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx -MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 -MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD -QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z -4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv -Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ -kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs -GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln -nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh -3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD -0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy -geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 -ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB -c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI -pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS -4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs -o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ -qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw -xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM -rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 -AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR -0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY -o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 -dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE -oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. -# Label: "TrustAsia Global Root CA G3" -# Serial: 576386314500428537169965010905813481816650257167 -# MD5 Fingerprint: 30:42:1b:b7:bb:81:75:35:e4:16:4f:53:d2:94:de:04 -# SHA1 Fingerprint: 63:cf:b6:c1:27:2b:56:e4:88:8e:1c:23:9a:b6:2e:81:47:24:c3:c7 -# SHA256 Fingerprint: e0:d3:22:6a:eb:11:63:c2:e4:8f:f9:be:3b:50:b4:c6:43:1b:e7:bb:1e:ac:c5:c3:6b:5d:5e:c5:09:03:9a:08 ------BEGIN CERTIFICATE----- -MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM -BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp -ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe -Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw -IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU -cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS -T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK -AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 -nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep -qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA -yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs -hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX -zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv -kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT -f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA -uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB -o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih -MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E -BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 -wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 -XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 -JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j -ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV -VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx -xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on -AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d -7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj -gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV -+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo -FGWsJwt0ivKH ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. -# Label: "TrustAsia Global Root CA G4" -# Serial: 451799571007117016466790293371524403291602933463 -# MD5 Fingerprint: 54:dd:b2:d7:5f:d8:3e:ed:7c:e0:0b:2e:cc:ed:eb:eb -# SHA1 Fingerprint: 57:73:a5:61:5d:80:b2:e6:ac:38:82:fc:68:07:31:ac:9f:b5:92:5a -# SHA256 Fingerprint: be:4b:56:cb:50:56:c0:13:6a:52:6d:f4:44:50:8d:aa:36:a0:b5:4f:42:e4:ac:38:f7:2a:f4:70:e4:79:65:4c ------BEGIN CERTIFICATE----- -MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw -WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y -MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD -VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz -dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx -s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw -LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij -YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD -pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE -AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR -UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj -/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== ------END CERTIFICATE----- - -# Issuer: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH -# Subject: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH -# Label: "Telekom Security TLS ECC Root 2020" -# Serial: 72082518505882327255703894282316633856 -# MD5 Fingerprint: c1:ab:fe:6a:10:2c:03:8d:bc:1c:22:32:c0:85:a7:fd -# SHA1 Fingerprint: c0:f8:96:c5:a9:3b:01:06:21:07:da:18:42:48:bc:e9:9d:88:d5:ec -# SHA256 Fingerprint: 57:8a:f4:de:d0:85:3f:4e:59:98:db:4a:ea:f9:cb:ea:8d:94:5f:60:b6:20:a3:8d:1a:3c:13:b2:bc:7b:a8:e1 ------BEGIN CERTIFICATE----- -MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw -CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH -bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw -MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx -JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE -AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O -tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP -f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA -MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di -z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn -27iQ7t0l ------END CERTIFICATE----- - -# Issuer: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH -# Subject: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH -# Label: "Telekom Security TLS RSA Root 2023" -# Serial: 44676229530606711399881795178081572759 -# MD5 Fingerprint: bf:5b:eb:54:40:cd:48:71:c4:20:8d:7d:de:0a:42:f2 -# SHA1 Fingerprint: 54:d3:ac:b3:bd:57:56:f6:85:9d:ce:e5:c3:21:e2:d4:ad:83:d0:93 -# SHA256 Fingerprint: ef:c6:5c:ad:bb:59:ad:b6:ef:e8:4d:a2:23:11:b3:56:24:b7:1b:3b:1e:a0:da:8b:66:55:17:4e:c8:97:86:46 ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj -MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 -eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy -MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC -REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG -A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 -cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV -cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA -U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 -Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug -BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy -8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J -co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg -8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 -rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 -mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg -+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX -gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 -p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ -pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm -9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw -M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd -GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ -CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t -xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ -w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK -L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj -X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q -ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm -dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= ------END CERTIFICATE----- - -# Issuer: CN=FIRMAPROFESIONAL CA ROOT-A WEB O=Firmaprofesional SA -# Subject: CN=FIRMAPROFESIONAL CA ROOT-A WEB O=Firmaprofesional SA -# Label: "FIRMAPROFESIONAL CA ROOT-A WEB" -# Serial: 65916896770016886708751106294915943533 -# MD5 Fingerprint: 82:b2:ad:45:00:82:b0:66:63:f8:5f:c3:67:4e:ce:a3 -# SHA1 Fingerprint: a8:31:11:74:a6:14:15:0d:ca:77:dd:0e:e4:0c:5d:58:fc:a0:72:a5 -# SHA256 Fingerprint: be:f2:56:da:f2:6e:9c:69:bd:ec:16:02:35:97:98:f3:ca:f7:18:21:a0:3e:01:82:57:c5:3c:65:61:7f:3d:4a ------BEGIN CERTIFICATE----- -MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQsw -CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE -YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB -IFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2WhcNNDcwMzMxMDkwMTM2WjBuMQsw -CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE -YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB -IFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zf -e9MEkVz6iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6C -cyvHZpsKjECcfIr28jlgst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB -/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FDY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0O -BBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO -PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw -hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG -XSaQpYXFuXqUPoeovQA= ------END CERTIFICATE----- - -# Issuer: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA CYBER Root CA" -# Serial: 85076849864375384482682434040119489222 -# MD5 Fingerprint: 0b:33:a0:97:52:95:d4:a9:fd:bb:db:6e:a3:55:5b:51 -# SHA1 Fingerprint: f6:b1:1c:1a:83:38:e9:7b:db:b3:a8:c8:33:24:e0:2d:9c:7f:26:66 -# SHA256 Fingerprint: 3f:63:bb:28:14:be:17:4e:c8:b6:43:9c:f0:8d:6d:56:f0:b7:c4:05:88:3a:56:48:a3:34:42:4d:6b:3e:c5:58 ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ -MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 -IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5 -WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO -LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg -Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P -40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF -avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/ -34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i -JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu -j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf -Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP -2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA -S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA -oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC -kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW -5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd -BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB -AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t -tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn -68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn -TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t -RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx -f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI -Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz -8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4 -NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX -xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6 -t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA12" -# Serial: 587887345431707215246142177076162061960426065942 -# MD5 Fingerprint: c6:89:ca:64:42:9b:62:08:49:0b:1e:7f:e9:07:3d:e8 -# SHA1 Fingerprint: 7a:22:1e:3d:de:1b:06:ac:9e:c8:47:70:16:8e:3c:e5:f7:6b:06:f4 -# SHA256 Fingerprint: 3f:03:4b:b5:70:4d:44:b2:d0:85:45:a0:20:57:de:93:eb:f3:90:5f:ce:72:1a:cb:c7:30:c0:6d:da:ee:90:4e ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u -LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgw -NTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD -eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS -b290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3emhF -KxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mt -p7JIKwccJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zd -J1M3s6oYwlkm7Fsf0uZlfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gur -FzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBFEaCeVESE99g2zvVQR9wsMJvuwPWW0v4J -hscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1UefNzFJM3IFTQy2VYzxV4+K -h9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsF -AAOCAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6Ld -mmQOmFxv3Y67ilQiLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJ -mBClnW8Zt7vPemVV2zfrPIpyMpcemik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA -8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPSvWKErI4cqc1avTc7bgoitPQV -55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhgaaaI5gdka9at/ -yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA14" -# Serial: 575790784512929437950770173562378038616896959179 -# MD5 Fingerprint: 71:0d:72:fa:92:19:65:5e:89:04:ac:16:33:f0:bc:d5 -# SHA1 Fingerprint: dd:50:c0:f7:79:b3:64:2e:74:a2:b8:9d:9f:d3:40:dd:bb:f0:f2:4f -# SHA256 Fingerprint: 4b:00:9c:10:34:49:4f:9a:b5:6b:ba:3b:a1:d6:27:31:fc:4d:20:d8:95:5a:dc:ec:10:a9:25:60:72:61:e3:38 ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM -BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u -LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw -NzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD -eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS -b290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh1oq/ -FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOg -vlIfX8xnbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy -6pJxaeQp8E+BgQQ8sqVb1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo -/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9J -kdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOEkJTRX45zGRBdAuVwpcAQ -0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSxjVIHvXib -y8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac -18izju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs -0Wq2XSqypWa9a4X0dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIAB -SMbHdPTGrMNASRZhdCyvjG817XsYAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVL -ApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeqYR3r6/wtbyPk -86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E -rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ib -ed87hwriZLoAymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopT -zfFP7ELyk+OZpDc8h7hi2/DsHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHS -DCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPGFrojutzdfhrGe0K22VoF3Jpf1d+4 -2kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6qnsb58Nn4DSEC5MUo -FlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/OfVy -K4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6 -dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl -Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB -365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c -JRNItX+S ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA15" -# Serial: 126083514594751269499665114766174399806381178503 -# MD5 Fingerprint: 13:30:fc:c4:62:a6:a9:de:b5:c1:68:af:b5:d2:31:47 -# SHA1 Fingerprint: cb:ba:83:c8:c1:5a:5d:f1:f9:73:6f:ca:d7:ef:28:13:06:4a:07:7d -# SHA256 Fingerprint: e7:78:f0:f0:95:fe:84:37:29:cd:1a:00:82:17:9e:53:14:a9:c2:91:44:28:05:e1:fb:1d:8f:b6:b8:88:6c:3a ------BEGIN CERTIFICATE----- -MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw -UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM -dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy -NTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJl -cnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBSb290 -IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5GdCx4 -wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSR -ZHX+AezB2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT -9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp -4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6 -bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH -# Subject: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH -# Label: "D-TRUST BR Root CA 2 2023" -# Serial: 153168538924886464690566649552453098598 -# MD5 Fingerprint: e1:09:ed:d3:60:d4:56:1b:47:1f:b7:0c:5f:1b:5f:85 -# SHA1 Fingerprint: 2d:b0:70:ee:71:94:af:69:68:17:db:79:ce:58:9f:a0:6b:96:f7:87 -# SHA256 Fingerprint: 05:52:e6:f8:3f:df:65:e8:fa:96:70:e6:66:df:28:a4:e2:13:40:b5:10:cb:e5:25:66:f9:7c:4f:b9:4b:2b:d1 ------BEGIN CERTIFICATE----- -MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBI -MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE -LVRSVVNUIEJSIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUw -OTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi -MCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCTcfKr -i3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNE -gXtRr90zsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8 -k12b9py0i4a6Ibn08OhZWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCT -Rphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl -2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LULQyReS2tNZ9/WtT5PeB+U -cSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIvx9gvdhFP -/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bS -uREVMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+ -0bpwHJwh5Q8xaRfX/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4N -DfTisl01gLmB1IRpkQLLddCNxbU9CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+ -XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZ5Dw1t61 -GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG -OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y -XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tI -FoE9c+CeJyrrd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67n -riv6uvw8l5VAk1/DLQOj7aRvU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTR -VFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4nj8+AybmTNudX0KEPUUDAxxZiMrc -LmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdijYQ6qgYF/6FKC0ULn -4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff/vtD -hQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsG -koHU6XCPpz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46 -ls/pdu4D58JDUjxqgejBWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aS -Ecr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/5usWDiJFAbzdNpQ0qTUmiteXue4Icr80 -knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jtn/mtd+ArY0+ew+43u3gJ -hJ65bvspmZDogNOfJA== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. -# Label: "TrustAsia TLS ECC Root CA" -# Serial: 310892014698942880364840003424242768478804666567 -# MD5 Fingerprint: 09:48:04:77:d2:fc:65:93:71:66:b1:11:95:4f:06:8c -# SHA1 Fingerprint: b5:ec:39:f3:a1:66:37:ae:c3:05:94:57:e2:be:11:be:b7:a1:7f:36 -# SHA256 Fingerprint: c0:07:6b:9e:f0:53:1f:b1:a6:56:d6:7c:4e:be:97:cd:5d:ba:a4:1e:f4:45:98:ac:c2:48:98:78:c9:2d:87:11 ------BEGIN CERTIFICATE----- -MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMw -WDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQw -NTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBYMQswCQYDVQQGEwJDTjElMCMGA1UE -ChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1c3RB -c2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/pVs/ -AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDp -guMqWzJ8S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAw -DgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01 -L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15KeAIxAKORh/IRM4PDwYqR -OkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. -# Label: "TrustAsia TLS RSA Root CA" -# Serial: 160405846464868906657516898462547310235378010780 -# MD5 Fingerprint: 3b:9e:c3:86:0f:34:3c:6b:c5:46:c4:8e:1d:e7:19:12 -# SHA1 Fingerprint: a5:46:50:c5:62:ea:95:9a:1a:a7:04:6f:17:58:c7:29:53:3d:03:fa -# SHA256 Fingerprint: 06:c0:8d:7d:af:d8:76:97:1e:b1:12:4f:e6:7f:84:7e:c0:c7:a1:58:d3:ea:53:cb:e9:40:e2:ea:97:91:f4:c3 ------BEGIN CERTIFICATE----- -MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEM -BQAwWDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dp -ZXMsIEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcN -MjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2WjBYMQswCQYDVQQGEwJDTjElMCMG -A1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1 -c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC -AgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+ -NmDQDIPNlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJ -Q1DNDX3eRA5gEk9bNb2/mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561 -HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fkzv93uMltrOXVmPGZLmzjyUT5tUMnCE32 -ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYozza/+lcK7Fs/6TAWe8Tb -xNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyrz2I8sMeX -i9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQ -UNoyIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+j -TnhMmCWr8n4uIF6CFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DT -bE3txci3OE9kxJRMT6DNrqXGJyV1J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8 -S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnTq1mt1tve1CuBAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZylomkadFK/hT -MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 -Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4 -iqME3mmL5Dw8veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt -7DlK9RME7I10nYEKqG/odv6LTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp -2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHxtlotJnMnlvm5P1vQiJ3koP26TpUJ -g3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp27RIGAAtvKLEiUUj -pQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87qqA8M -pugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongP -XvPKnbwbPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIwe -SsCI3zWQzj8C9GRh3sfIB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0 -ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNzFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy -323imttUQ/hHWKNddBWcwauwxzQ= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH -# Subject: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH -# Label: "D-TRUST EV Root CA 2 2023" -# Serial: 139766439402180512324132425437959641711 -# MD5 Fingerprint: 96:b4:78:09:f0:09:cb:77:eb:bb:1b:4d:6f:36:bc:b6 -# SHA1 Fingerprint: a5:5b:d8:47:6c:8f:19:f7:4c:f4:6d:6b:b6:c2:79:82:22:df:54:8b -# SHA256 Fingerprint: 8e:82:21:b2:e7:d4:00:78:36:a1:67:2f:0d:cc:29:9c:33:bc:07:d3:16:f1:32:fa:1a:20:6d:58:71:50:f1:ce ------BEGIN CERTIFICATE----- -MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBI -MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE -LVRSVVNUIEVWIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUw -OTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi -MCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1sJkK -F8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE -7CUXFId/MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFe -EMbsh2aJgWi6zCudR3Mfvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6 -lHPTGGkKSv/BAQP/eX+1SH977ugpbzZMlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIb -RlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3YG14C8qKXO0elg6DpkiV -jTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq9107PncjLgc -jmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZx -TnXonMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ -ARZZaBhDM7DS3LAaQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nk -hbDhezGdpn9yo7nELC7MmVcOIQxFAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knF -NXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqvyREBuH -kV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG -OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y -XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14 -QvBukEdHjqOSMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4 -pZt+UPJ26oUFKidBK7GB0aL2QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q -3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xDUmPBEcrCRbH0O1P1aa4846XerOhU -t7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V4U/M5d40VxDJI3IX -cI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuodNv8 -ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT -2vFp4LJiTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs -7dpn1mKmS00PaaLJvOwiS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNP -gofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAst -Nl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L+KIkBI3Y4WNeApI02phh -XBxvWHZks/wCuPWdCg== ------END CERTIFICATE----- - -# Issuer: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG -# Subject: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG -# Label: "SwissSign RSA TLS Root CA 2022 - 1" -# Serial: 388078645722908516278762308316089881486363258315 -# MD5 Fingerprint: 16:2e:e4:19:76:81:85:ba:8e:91:58:f1:15:ef:72:39 -# SHA1 Fingerprint: 81:34:0a:be:4c:cd:ce:cc:e7:7d:cc:8a:d4:57:e2:45:a0:77:5d:ce -# SHA256 Fingerprint: 19:31:44:f4:31:e0:fd:db:74:07:17:d4:de:92:6a:57:11:33:88:4b:43:60:d3:0e:27:29:13:cb:e6:60:ce:41 ------BEGIN CERTIFICATE----- -MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UE -AxMiU3dpc3NTaWduIFJTQSBUTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgx -MTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxT -d2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0EgVExTIFJvb3QgQ0Eg -MjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmjiC8NX -vDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7 -LCTLf5ImgKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX -5XH8irCRIFucdFJtrhUnWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyE -EPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlfGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt -/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36qOTw7D59Ke4LKa2/KIj4x -0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLOEGrOyvi5 -KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM -0ZPlEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shd -OxtYk8EXlFXIC+OCeYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrta -clXvyFu1cvh43zcgTFeRc5JzrBh3Q4IgaezprClG5QtO+DdziZaKHG29777YtvTK -wP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQABo2MwYTAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow4UD2p8P98Q+4 -DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL -BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO3 -10aewCoSPY6WlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgz -Hqp41eZUBDqyggmNzhYzWUUo8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQ -iJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zpy1FVCypM9fJkT6lc/2cyjlUtMoIc -gC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3CjlvrzG4ngRhZi0Rjn9UM -ZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6MOuhF -LhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJp -zv1/THfQwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/Td -Ao9QAwKxuDdollDruF/UKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0 -rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0nhzck5npgL7XTgwSqT0N1osGDsieYK7EO -gLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rwtnu64ZzZ ------END CERTIFICATE----- - -# Issuer: CN=OISTE Server Root ECC G1 O=OISTE Foundation -# Subject: CN=OISTE Server Root ECC G1 O=OISTE Foundation -# Label: "OISTE Server Root ECC G1" -# Serial: 47819833811561661340092227008453318557 -# MD5 Fingerprint: 42:a7:d2:35:ae:02:92:db:19:76:08:de:2f:05:b4:d4 -# SHA1 Fingerprint: 3b:f6:8b:09:ae:2a:92:7b:ba:e3:8d:3f:11:95:d9:e6:44:0c:45:e2 -# SHA256 Fingerprint: ee:c9:97:c0:c3:0f:21:6f:7e:3b:8b:30:7d:2b:ae:42:41:2d:75:3f:c8:21:9d:af:d1:52:0b:25:72:85:0f:49 ------BEGIN CERTIFICATE----- -MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQsw -CQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwY -T0lTVEUgU2VydmVyIFJvb3QgRUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUy -NDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRp -b24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBHMTB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOujvqQy -cvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N -2xml4z+cKrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3 -TYhlz/w9itWj8UnATgwQb0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9C -tJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCpKjAd0MKfkFFR -QD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxgZzFDJe0CMQCSia7pXGKD -YmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c= ------END CERTIFICATE----- - -# Issuer: CN=OISTE Server Root RSA G1 O=OISTE Foundation -# Subject: CN=OISTE Server Root RSA G1 O=OISTE Foundation -# Label: "OISTE Server Root RSA G1" -# Serial: 113845518112613905024960613408179309848 -# MD5 Fingerprint: 23:a7:9e:d4:70:b8:b9:14:57:41:8a:7e:44:59:e2:68 -# SHA1 Fingerprint: f7:00:34:25:94:88:68:31:e4:34:87:3f:70:fe:86:b3:86:9f:f0:6e -# SHA256 Fingerprint: 9a:e3:62:32:a5:18:9f:fd:db:35:3d:fd:26:52:0c:01:53:95:d2:27:77:da:c5:9d:b5:7b:98:c0:89:a6:51:e6 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBL -MQswCQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UE -AwwYT0lTVEUgU2VydmVyIFJvb3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4 -MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5k -YXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJTQSBHMTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxVYOPM -vLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7b -rEi56rAUjtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzk -ik/HEzxux9UTl7Ko2yRpg1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4z -O8vbUZeUapU8zhhabkvG/AePLhq5SvdkNCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8R -tOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY+m0o/DjH40ytas7ZTpOS -jswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+lKXHiHUh -sd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+Ho -mnqT8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu -+zrkL8Fl47l6QGzwBrd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYR -i3drVByjtdgQ8K4p92cIiBdcuJd5z+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnT -kCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU -8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC77EUOSh+1sbM2 -zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33 -I3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG -5D1rd9QhEOP28yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8 -qyiWXmFcuCIzGEgWUOrKL+mlSdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dP -AGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l8PjaV8GUgeV6Vg27Rn9vkf195hfk -gSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+FKrDgHGdPY3ofRRs -YWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNqqYY1 -9tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome -/msVuduCmsuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3 -J8tRd/iWkx7P8nd9H0aTolkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2 -wq1yVAb+axj5d9spLFKebXd7Yv0PTY6YMjAwcRLWJTXjn/hvnLXrahut6hDTlhZy -BiElxky8j3C7DOReIoMt0r7+hVu05L0= ------END CERTIFICATE----- - -# Issuer: CN=e-Szigno TLS Root CA 2023 O=Microsec Ltd. -# Subject: CN=e-Szigno TLS Root CA 2023 O=Microsec Ltd. -# Label: "e-Szigno TLS Root CA 2023" -# Serial: 71934828665710877219916191754 -# MD5 Fingerprint: 6a:e9:99:74:a5:da:5e:f1:d9:2e:f2:c8:d1:86:8b:71 -# SHA1 Fingerprint: 6f:9a:d5:d5:df:e8:2c:eb:be:37:07:ee:4f:4f:52:58:29:41:d1:fe -# SHA256 Fingerprint: b4:91:41:50:2d:00:66:3d:74:0f:2e:7e:c3:40:c5:28:00:96:26:66:12:1a:36:d0:9c:f7:dd:2b:90:38:4f:b4 ------BEGIN CERTIFICATE----- -MIICzzCCAjGgAwIBAgINAOhvGHvWOWuYSkmYCjAKBggqhkjOPQQDBDB1MQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSIwIAYDVQQDDBllLVN6aWdubyBU -TFMgUm9vdCBDQSAyMDIzMB4XDTIzMDcxNzE0MDAwMFoXDTM4MDcxNzE0MDAwMFow -dTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNy -b3NlYyBMdGQuMRcwFQYDVQRhDA5WQVRIVS0yMzU4NDQ5NzEiMCAGA1UEAwwZZS1T -emlnbm8gVExTIFJvb3QgQ0EgMjAyMzCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAE -AGgP36J8PKp0iGEKjcJMpQEiFNT3YHdCnAo4YKGMZz6zY+n6kbCLS+Y53wLCMAFS -AL/fjO1ZrTJlqwlZULUZwmgcAOAFX9pQJhzDrAQixTpN7+lXWDajwRlTEArRzT/v -SzUaQ49CE0y5LBqcvjC2xN7cS53kpDzLLtmt3999Cd8ukv+ho2MwYTAPBgNVHRMB -Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUWYQCYlpGePVd3I8K -ECgj3NXW+0UwHwYDVR0jBBgwFoAUWYQCYlpGePVd3I8KECgj3NXW+0UwCgYIKoZI -zj0EAwQDgYsAMIGHAkIBLdqu9S54tma4n7Zwf2Z0z+yOfP7AAXmazlIC58PRDHpt -y7Ve7hekm9sEdu4pKeiv+62sUvTXK9Z3hBC9xdIoaDQCQTV2WnXzkoYI9bIeCvZl -C9p2x1L/Cx6AcCIwwzPbGO2E14vs7dOoY4G1VnxHx1YwlGhza9IuqbnZLBwpvQy6 -uWWL ------END CERTIFICATE----- diff --git a/venv/lib/python3.10/site-packages/certifi/core.py b/venv/lib/python3.10/site-packages/certifi/core.py deleted file mode 100644 index 1c9661cc7c2f6917c2506a30b2710002f81ab23a..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/certifi/core.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -certifi.py -~~~~~~~~~~ - -This module returns the installation location of cacert.pem or its contents. -""" -import sys -import atexit - -def exit_cacert_ctx() -> None: - _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] - - -if sys.version_info >= (3, 11): - - from importlib.resources import as_file, files - - _CACERT_CTX = None - _CACERT_PATH = None - - def where() -> str: - # This is slightly terrible, but we want to delay extracting the file - # in cases where we're inside of a zipimport situation until someone - # actually calls where(), but we don't want to re-extract the file - # on every call of where(), so we'll do it once then store it in a - # global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you to - # manage the cleanup of this file, so it doesn't actually return a - # path, it returns a context manager that will give you the path - # when you enter it and will do any cleanup when you leave it. In - # the common case of not needing a temporary file, it will just - # return the file system location and the __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - atexit.register(exit_cacert_ctx) - - return _CACERT_PATH - - def contents() -> str: - return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") - -else: - - from importlib.resources import path as get_path, read_text - - _CACERT_CTX = None - _CACERT_PATH = None - - def where() -> str: - # This is slightly terrible, but we want to delay extracting the - # file in cases where we're inside of a zipimport situation until - # someone actually calls where(), but we don't want to re-extract - # the file on every call of where(), so we'll do it once then store - # it in a global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you - # to manage the cleanup of this file, so it doesn't actually - # return a path, it returns a context manager that will give - # you the path when you enter it and will do any cleanup when - # you leave it. In the common case of not needing a temporary - # file, it will just return the file system location and the - # __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = get_path("certifi", "cacert.pem") - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - atexit.register(exit_cacert_ctx) - - return _CACERT_PATH - - def contents() -> str: - return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/venv/lib/python3.10/site-packages/certifi/py.typed b/venv/lib/python3.10/site-packages/certifi/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/METADATA b/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/METADATA deleted file mode 100644 index 3f433afb9c48912fe13fc7b24a0e71874c675822..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/METADATA +++ /dev/null @@ -1,84 +0,0 @@ -Metadata-Version: 2.4 -Name: click -Version: 8.3.1 -Summary: Composable command line interface toolkit -Maintainer-email: Pallets -Requires-Python: >=3.10 -Description-Content-Type: text/markdown -License-Expression: BSD-3-Clause -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Typing :: Typed -License-File: LICENSE.txt -Requires-Dist: colorama; platform_system == 'Windows' -Project-URL: Changes, https://click.palletsprojects.com/page/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://click.palletsprojects.com/ -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Source, https://github.com/pallets/click/ - -
- -# Click - -Click is a Python package for creating beautiful command line interfaces -in a composable way with as little code as necessary. It's the "Command -Line Interface Creation Kit". It's highly configurable but comes with -sensible defaults out of the box. - -It aims to make the process of writing command line tools quick and fun -while also preventing any frustration caused by the inability to -implement an intended CLI API. - -Click in three points: - -- Arbitrary nesting of commands -- Automatic help page generation -- Supports lazy loading of subcommands at runtime - - -## A Simple Example - -```python -import click - -@click.command() -@click.option("--count", default=1, help="Number of greetings.") -@click.option("--name", prompt="Your name", help="The person to greet.") -def hello(count, name): - """Simple program that greets NAME for a total of COUNT times.""" - for _ in range(count): - click.echo(f"Hello, {name}!") - -if __name__ == '__main__': - hello() -``` - -``` -$ python hello.py --count=3 -Your name: Click -Hello, Click! -Hello, Click! -Hello, Click! -``` - - -## Donate - -The Pallets organization develops and supports Click and other popular -packages. In order to grow the community of contributors and users, and -allow the maintainers to devote more time to the projects, [please -donate today][]. - -[please donate today]: https://palletsprojects.com/donate - -## Contributing - -See our [detailed contributing documentation][contrib] for many ways to -contribute, including reporting issues, requesting features, asking or answering -questions, and making PRs. - -[contrib]: https://palletsprojects.com/contributing/ - diff --git a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/RECORD b/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/RECORD deleted file mode 100644 index 839aadeaba065309d29eb411d38cd448585da943..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/RECORD +++ /dev/null @@ -1,40 +0,0 @@ -click-8.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -click-8.3.1.dist-info/METADATA,sha256=XZeBrMAE0ghTE88SjfrSDuSyNCpBPplxJR1tbwD9oZg,2621 -click-8.3.1.dist-info/RECORD,, -click-8.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -click-8.3.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 -click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473 -click/__pycache__/__init__.cpython-310.pyc,, -click/__pycache__/_compat.cpython-310.pyc,, -click/__pycache__/_termui_impl.cpython-310.pyc,, -click/__pycache__/_textwrap.cpython-310.pyc,, -click/__pycache__/_utils.cpython-310.pyc,, -click/__pycache__/_winconsole.cpython-310.pyc,, -click/__pycache__/core.cpython-310.pyc,, -click/__pycache__/decorators.cpython-310.pyc,, -click/__pycache__/exceptions.cpython-310.pyc,, -click/__pycache__/formatting.cpython-310.pyc,, -click/__pycache__/globals.cpython-310.pyc,, -click/__pycache__/parser.cpython-310.pyc,, -click/__pycache__/shell_completion.cpython-310.pyc,, -click/__pycache__/termui.cpython-310.pyc,, -click/__pycache__/testing.cpython-310.pyc,, -click/__pycache__/types.cpython-310.pyc,, -click/__pycache__/utils.cpython-310.pyc,, -click/_compat.py,sha256=v3xBZkFbvA1BXPRkFfBJc6-pIwPI7345m-kQEnpVAs4,18693 -click/_termui_impl.py,sha256=rgCb3On8X5A4200rA5L6i13u5iapmFer7sru57Jy6zA,27093 -click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400 -click/_utils.py,sha256=kZwtTf5gMuCilJJceS2iTCvRvCY-0aN5rJq8gKw7p8g,943 -click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465 -click/core.py,sha256=U6Bfxt8GkjNDqyJ0HqXvluJHtyZ4sY5USAvM1Cdq7mQ,132105 -click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461 -click/exceptions.py,sha256=8utf8w6V5hJXMnO_ic1FNrtbwuEn1NUu1aDwV8UqnG4,9954 -click/formatting.py,sha256=RVfwwr0rwWNpgGr8NaHodPzkIr7_tUyVh_nDdanLMNc,9730 -click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 -click/parser.py,sha256=Q31pH0FlQZEq-UXE_ABRzlygEfvxPTuZbWNh4xfXmzw,19010 -click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -click/shell_completion.py,sha256=Cc4GQUFuWpfQBa9sF5qXeeYI7n3tI_1k6ZdSn4BZbT0,20994 -click/termui.py,sha256=hqCEjNndU-nzW08nRAkBaVgfZp_FdCA9KxfIWlKYaMc,31037 -click/testing.py,sha256=EERbzcl1br0mW0qBS9EqkknfNfXB9WQEW0ELIpkvuSs,19102 -click/types.py,sha256=ek54BNSFwPKsqtfT7jsqcc4WHui8AIFVMKM4oVZIXhc,39927 -click/utils.py,sha256=gCUoewdAhA-QLBUUHxrLh4uj6m7T1WjZZMNPvR0I7YA,20257 diff --git a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/WHEEL b/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/WHEEL deleted file mode 100644 index d8b9936dad9ab2513fa6979f411560d3b6b57e37..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt b/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt deleted file mode 100644 index d12a849186982399c537c5b9a8fd77bf2edd5eab..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2014 Pallets - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.10/site-packages/click/__init__.py b/venv/lib/python3.10/site-packages/click/__init__.py deleted file mode 100644 index 1aa547c57af68954b3bcd6012873881030e53d91..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/__init__.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -Click is a simple Python module inspired by the stdlib optparse to make -writing command line scripts fun. Unlike other modules, it's based -around a simple API that does not come with too much magic and is -composable. -""" - -from __future__ import annotations - -from .core import Argument as Argument -from .core import Command as Command -from .core import CommandCollection as CommandCollection -from .core import Context as Context -from .core import Group as Group -from .core import Option as Option -from .core import Parameter as Parameter -from .decorators import argument as argument -from .decorators import command as command -from .decorators import confirmation_option as confirmation_option -from .decorators import group as group -from .decorators import help_option as help_option -from .decorators import make_pass_decorator as make_pass_decorator -from .decorators import option as option -from .decorators import pass_context as pass_context -from .decorators import pass_obj as pass_obj -from .decorators import password_option as password_option -from .decorators import version_option as version_option -from .exceptions import Abort as Abort -from .exceptions import BadArgumentUsage as BadArgumentUsage -from .exceptions import BadOptionUsage as BadOptionUsage -from .exceptions import BadParameter as BadParameter -from .exceptions import ClickException as ClickException -from .exceptions import FileError as FileError -from .exceptions import MissingParameter as MissingParameter -from .exceptions import NoSuchOption as NoSuchOption -from .exceptions import UsageError as UsageError -from .formatting import HelpFormatter as HelpFormatter -from .formatting import wrap_text as wrap_text -from .globals import get_current_context as get_current_context -from .termui import clear as clear -from .termui import confirm as confirm -from .termui import echo_via_pager as echo_via_pager -from .termui import edit as edit -from .termui import getchar as getchar -from .termui import launch as launch -from .termui import pause as pause -from .termui import progressbar as progressbar -from .termui import prompt as prompt -from .termui import secho as secho -from .termui import style as style -from .termui import unstyle as unstyle -from .types import BOOL as BOOL -from .types import Choice as Choice -from .types import DateTime as DateTime -from .types import File as File -from .types import FLOAT as FLOAT -from .types import FloatRange as FloatRange -from .types import INT as INT -from .types import IntRange as IntRange -from .types import ParamType as ParamType -from .types import Path as Path -from .types import STRING as STRING -from .types import Tuple as Tuple -from .types import UNPROCESSED as UNPROCESSED -from .types import UUID as UUID -from .utils import echo as echo -from .utils import format_filename as format_filename -from .utils import get_app_dir as get_app_dir -from .utils import get_binary_stream as get_binary_stream -from .utils import get_text_stream as get_text_stream -from .utils import open_file as open_file - - -def __getattr__(name: str) -> object: - import warnings - - if name == "BaseCommand": - from .core import _BaseCommand - - warnings.warn( - "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Command' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _BaseCommand - - if name == "MultiCommand": - from .core import _MultiCommand - - warnings.warn( - "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Group' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _MultiCommand - - if name == "OptionParser": - from .parser import _OptionParser - - warnings.warn( - "'OptionParser' is deprecated and will be removed in Click 9.0. The" - " old parser is available in 'optparse'.", - DeprecationWarning, - stacklevel=2, - ) - return _OptionParser - - if name == "__version__": - import importlib.metadata - import warnings - - warnings.warn( - "The '__version__' attribute is deprecated and will be removed in" - " Click 9.1. Use feature detection or" - " 'importlib.metadata.version(\"click\")' instead.", - DeprecationWarning, - stacklevel=2, - ) - return importlib.metadata.version("click") - - raise AttributeError(name) diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 255a8b1bc27428eb825e614c8fcc588fedfa9061..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc deleted file mode 100644 index 408e5b2140dd5635e38623693a35c1d262b31b7b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc deleted file mode 100644 index 39465ea2493bcdf4de8f6e89044a14f205c65ec1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc deleted file mode 100644 index 6b6a1a5a9dba7482cf48cc19bedc657b2452e447..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/_utils.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/_utils.cpython-310.pyc deleted file mode 100644 index ad8361a6513c8e6ea7990a18450b4482e84ac7cb..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/_utils.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/_winconsole.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/_winconsole.cpython-310.pyc deleted file mode 100644 index 6966476b07ff36e8eee6f132d22c6fd8ec501f2e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/_winconsole.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc deleted file mode 100644 index 3c10d7529364b7683199a041908ec0e1b4602aab..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/decorators.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/decorators.cpython-310.pyc deleted file mode 100644 index 5c4ff1703d78334ea5c1d68b5eb6942acf66a2ce..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/decorators.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/exceptions.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/exceptions.cpython-310.pyc deleted file mode 100644 index 6901d08613677617f624127d57f790886f3e19ed..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/exceptions.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/formatting.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/formatting.cpython-310.pyc deleted file mode 100644 index 49fc479c7eeff8fa75628122161bb7895ce1479b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/formatting.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc deleted file mode 100644 index b821979c27646fd34ace13767612b56f8119af12..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/parser.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/parser.cpython-310.pyc deleted file mode 100644 index 6a6e47a2f7dd35d32523dbafde70b1a14b929559..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/parser.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/shell_completion.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/shell_completion.cpython-310.pyc deleted file mode 100644 index d31808d86db84d8847beaa9a409d20713a64218c..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/shell_completion.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/termui.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/termui.cpython-310.pyc deleted file mode 100644 index 6065c88e5a27ee25a7491d5ff8eb90ae1a336443..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/termui.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc deleted file mode 100644 index f5a0eee831725afa30e2eebe30eef6064a97375f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/types.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/types.cpython-310.pyc deleted file mode 100644 index 5a996cfac3523677017fbd21c2dec197f3d1c6a4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/types.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc b/venv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc deleted file mode 100644 index 2203896ed07fe7b405afe52fc010d51786bfaa97..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/click/_compat.py b/venv/lib/python3.10/site-packages/click/_compat.py deleted file mode 100644 index f2726b93afe2ed69ba20d8e709c9cbd22b9d2339..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/_compat.py +++ /dev/null @@ -1,622 +0,0 @@ -from __future__ import annotations - -import codecs -import collections.abc as cabc -import io -import os -import re -import sys -import typing as t -from types import TracebackType -from weakref import WeakKeyDictionary - -CYGWIN = sys.platform.startswith("cygwin") -WIN = sys.platform.startswith("win") -auto_wrap_for_ansi: t.Callable[[t.TextIO], t.TextIO] | None = None -_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") - - -def _make_text_stream( - stream: t.BinaryIO, - encoding: str | None, - errors: str | None, - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if encoding is None: - encoding = get_best_encoding(stream) - if errors is None: - errors = "replace" - return _NonClosingTextIOWrapper( - stream, - encoding, - errors, - line_buffering=True, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def is_ascii_encoding(encoding: str) -> bool: - """Checks if a given encoding is ascii.""" - try: - return codecs.lookup(encoding).name == "ascii" - except LookupError: - return False - - -def get_best_encoding(stream: t.IO[t.Any]) -> str: - """Returns the default stream encoding if not found.""" - rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() - if is_ascii_encoding(rv): - return "utf-8" - return rv - - -class _NonClosingTextIOWrapper(io.TextIOWrapper): - def __init__( - self, - stream: t.BinaryIO, - encoding: str | None, - errors: str | None, - force_readable: bool = False, - force_writable: bool = False, - **extra: t.Any, - ) -> None: - self._stream = stream = t.cast( - t.BinaryIO, _FixupStream(stream, force_readable, force_writable) - ) - super().__init__(stream, encoding, errors, **extra) - - def __del__(self) -> None: - try: - self.detach() - except Exception: - pass - - def isatty(self) -> bool: - # https://bitbucket.org/pypy/pypy/issue/1803 - return self._stream.isatty() - - -class _FixupStream: - """The new io interface needs more from streams than streams - traditionally implement. As such, this fix-up code is necessary in - some circumstances. - - The forcing of readable and writable flags are there because some tools - put badly patched objects on sys (one such offender are certain version - of jupyter notebook). - """ - - def __init__( - self, - stream: t.BinaryIO, - force_readable: bool = False, - force_writable: bool = False, - ): - self._stream = stream - self._force_readable = force_readable - self._force_writable = force_writable - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._stream, name) - - def read1(self, size: int) -> bytes: - f = getattr(self._stream, "read1", None) - - if f is not None: - return t.cast(bytes, f(size)) - - return self._stream.read(size) - - def readable(self) -> bool: - if self._force_readable: - return True - x = getattr(self._stream, "readable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.read(0) - except Exception: - return False - return True - - def writable(self) -> bool: - if self._force_writable: - return True - x = getattr(self._stream, "writable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.write(b"") - except Exception: - try: - self._stream.write(b"") - except Exception: - return False - return True - - def seekable(self) -> bool: - x = getattr(self._stream, "seekable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.seek(self._stream.tell()) - except Exception: - return False - return True - - -def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - return isinstance(stream.read(0), bytes) - except Exception: - return default - # This happens in some cases where the stream was already - # closed. In this case, we assume the default. - - -def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - stream.write(b"") - except Exception: - try: - stream.write("") - return False - except Exception: - pass - return default - return True - - -def _find_binary_reader(stream: t.IO[t.Any]) -> t.BinaryIO | None: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_reader(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_reader(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _find_binary_writer(stream: t.IO[t.Any]) -> t.BinaryIO | None: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_writer(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_writer(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _stream_is_misconfigured(stream: t.TextIO) -> bool: - """A stream is misconfigured if its encoding is ASCII.""" - # If the stream does not have an encoding set, we assume it's set - # to ASCII. This appears to happen in certain unittest - # environments. It's not quite clear what the correct behavior is - # but this at least will force Click to recover somehow. - return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") - - -def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: str | None) -> bool: - """A stream attribute is compatible if it is equal to the - desired value or the desired value is unset and the attribute - has a value. - """ - stream_value = getattr(stream, attr, None) - return stream_value == value or (value is None and stream_value is not None) - - -def _is_compatible_text_stream( - stream: t.TextIO, encoding: str | None, errors: str | None -) -> bool: - """Check if a stream's encoding and errors attributes are - compatible with the desired values. - """ - return _is_compat_stream_attr( - stream, "encoding", encoding - ) and _is_compat_stream_attr(stream, "errors", errors) - - -def _force_correct_text_stream( - text_stream: t.IO[t.Any], - encoding: str | None, - errors: str | None, - is_binary: t.Callable[[t.IO[t.Any], bool], bool], - find_binary: t.Callable[[t.IO[t.Any]], t.BinaryIO | None], - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if is_binary(text_stream, False): - binary_reader = t.cast(t.BinaryIO, text_stream) - else: - text_stream = t.cast(t.TextIO, text_stream) - # If the stream looks compatible, and won't default to a - # misconfigured ascii encoding, return it as-is. - if _is_compatible_text_stream(text_stream, encoding, errors) and not ( - encoding is None and _stream_is_misconfigured(text_stream) - ): - return text_stream - - # Otherwise, get the underlying binary reader. - possible_binary_reader = find_binary(text_stream) - - # If that's not possible, silently use the original reader - # and get mojibake instead of exceptions. - if possible_binary_reader is None: - return text_stream - - binary_reader = possible_binary_reader - - # Default errors to replace instead of strict in order to get - # something that works. - if errors is None: - errors = "replace" - - # Wrap the binary stream in a text stream with the correct - # encoding parameters. - return _make_text_stream( - binary_reader, - encoding, - errors, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def _force_correct_text_reader( - text_reader: t.IO[t.Any], - encoding: str | None, - errors: str | None, - force_readable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_reader, - encoding, - errors, - _is_binary_reader, - _find_binary_reader, - force_readable=force_readable, - ) - - -def _force_correct_text_writer( - text_writer: t.IO[t.Any], - encoding: str | None, - errors: str | None, - force_writable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_writer, - encoding, - errors, - _is_binary_writer, - _find_binary_writer, - force_writable=force_writable, - ) - - -def get_binary_stdin() -> t.BinaryIO: - reader = _find_binary_reader(sys.stdin) - if reader is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdin.") - return reader - - -def get_binary_stdout() -> t.BinaryIO: - writer = _find_binary_writer(sys.stdout) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdout.") - return writer - - -def get_binary_stderr() -> t.BinaryIO: - writer = _find_binary_writer(sys.stderr) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stderr.") - return writer - - -def get_text_stdin(encoding: str | None = None, errors: str | None = None) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdin, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) - - -def get_text_stdout(encoding: str | None = None, errors: str | None = None) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdout, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) - - -def get_text_stderr(encoding: str | None = None, errors: str | None = None) -> t.TextIO: - rv = _get_windows_console_stream(sys.stderr, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) - - -def _wrap_io_open( - file: str | os.PathLike[str] | int, - mode: str, - encoding: str | None, - errors: str | None, -) -> t.IO[t.Any]: - """Handles not passing ``encoding`` and ``errors`` in binary mode.""" - if "b" in mode: - return open(file, mode) - - return open(file, mode, encoding=encoding, errors=errors) - - -def open_stream( - filename: str | os.PathLike[str], - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - atomic: bool = False, -) -> tuple[t.IO[t.Any], bool]: - binary = "b" in mode - filename = os.fspath(filename) - - # Standard streams first. These are simple because they ignore the - # atomic flag. Use fsdecode to handle Path("-"). - if os.fsdecode(filename) == "-": - if any(m in mode for m in ["w", "a", "x"]): - if binary: - return get_binary_stdout(), False - return get_text_stdout(encoding=encoding, errors=errors), False - if binary: - return get_binary_stdin(), False - return get_text_stdin(encoding=encoding, errors=errors), False - - # Non-atomic writes directly go out through the regular open functions. - if not atomic: - return _wrap_io_open(filename, mode, encoding, errors), True - - # Some usability stuff for atomic writes - if "a" in mode: - raise ValueError( - "Appending to an existing file is not supported, because that" - " would involve an expensive `copy`-operation to a temporary" - " file. Open the file in normal `w`-mode and copy explicitly" - " if that's what you're after." - ) - if "x" in mode: - raise ValueError("Use the `overwrite`-parameter instead.") - if "w" not in mode: - raise ValueError("Atomic writes only make sense with `w`-mode.") - - # Atomic writes are more complicated. They work by opening a file - # as a proxy in the same folder and then using the fdopen - # functionality to wrap it in a Python file. Then we wrap it in an - # atomic file that moves the file over on close. - import errno - import random - - try: - perm: int | None = os.stat(filename).st_mode - except OSError: - perm = None - - flags = os.O_RDWR | os.O_CREAT | os.O_EXCL - - if binary: - flags |= getattr(os, "O_BINARY", 0) - - while True: - tmp_filename = os.path.join( - os.path.dirname(filename), - f".__atomic-write{random.randrange(1 << 32):08x}", - ) - try: - fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) - break - except OSError as e: - if e.errno == errno.EEXIST or ( - os.name == "nt" - and e.errno == errno.EACCES - and os.path.isdir(e.filename) - and os.access(e.filename, os.W_OK) - ): - continue - raise - - if perm is not None: - os.chmod(tmp_filename, perm) # in case perm includes bits in umask - - f = _wrap_io_open(fd, mode, encoding, errors) - af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) - return t.cast(t.IO[t.Any], af), True - - -class _AtomicFile: - def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: - self._f = f - self._tmp_filename = tmp_filename - self._real_filename = real_filename - self.closed = False - - @property - def name(self) -> str: - return self._real_filename - - def close(self, delete: bool = False) -> None: - if self.closed: - return - self._f.close() - os.replace(self._tmp_filename, self._real_filename) - self.closed = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._f, name) - - def __enter__(self) -> _AtomicFile: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.close(delete=exc_type is not None) - - def __repr__(self) -> str: - return repr(self._f) - - -def strip_ansi(value: str) -> str: - return _ansi_re.sub("", value) - - -def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: - while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): - stream = stream._stream - - return stream.__class__.__module__.startswith("ipykernel.") - - -def should_strip_ansi( - stream: t.IO[t.Any] | None = None, color: bool | None = None -) -> bool: - if color is None: - if stream is None: - stream = sys.stdin - return not isatty(stream) and not _is_jupyter_kernel_output(stream) - return not color - - -# On Windows, wrap the output streams with colorama to support ANSI -# color codes. -# NOTE: double check is needed so mypy does not analyze this on Linux -if sys.platform.startswith("win") and WIN: - from ._winconsole import _get_windows_console_stream - - def _get_argv_encoding() -> str: - import locale - - return locale.getpreferredencoding() - - _ansi_stream_wrappers: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def auto_wrap_for_ansi(stream: t.TextIO, color: bool | None = None) -> t.TextIO: - """Support ANSI color and style codes on Windows by wrapping a - stream with colorama. - """ - try: - cached = _ansi_stream_wrappers.get(stream) - except Exception: - cached = None - - if cached is not None: - return cached - - import colorama - - strip = should_strip_ansi(stream, color) - ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) - rv = t.cast(t.TextIO, ansi_wrapper.stream) - _write = rv.write - - def _safe_write(s: str) -> int: - try: - return _write(s) - except BaseException: - ansi_wrapper.reset_all() - raise - - rv.write = _safe_write # type: ignore[method-assign] - - try: - _ansi_stream_wrappers[stream] = rv - except Exception: - pass - - return rv - -else: - - def _get_argv_encoding() -> str: - return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() - - def _get_windows_console_stream( - f: t.TextIO, encoding: str | None, errors: str | None - ) -> t.TextIO | None: - return None - - -def term_len(x: str) -> int: - return len(strip_ansi(x)) - - -def isatty(stream: t.IO[t.Any]) -> bool: - try: - return stream.isatty() - except Exception: - return False - - -def _make_cached_stream_func( - src_func: t.Callable[[], t.TextIO | None], - wrapper_func: t.Callable[[], t.TextIO], -) -> t.Callable[[], t.TextIO | None]: - cache: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def func() -> t.TextIO | None: - stream = src_func() - - if stream is None: - return None - - try: - rv = cache.get(stream) - except Exception: - rv = None - if rv is not None: - return rv - rv = wrapper_func() - try: - cache[stream] = rv - except Exception: - pass - return rv - - return func - - -_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) -_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) -_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) - - -binary_streams: cabc.Mapping[str, t.Callable[[], t.BinaryIO]] = { - "stdin": get_binary_stdin, - "stdout": get_binary_stdout, - "stderr": get_binary_stderr, -} - -text_streams: cabc.Mapping[str, t.Callable[[str | None, str | None], t.TextIO]] = { - "stdin": get_text_stdin, - "stdout": get_text_stdout, - "stderr": get_text_stderr, -} diff --git a/venv/lib/python3.10/site-packages/click/_termui_impl.py b/venv/lib/python3.10/site-packages/click/_termui_impl.py deleted file mode 100644 index ee8225c4c29344e6c672800f97f65322d245e166..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/_termui_impl.py +++ /dev/null @@ -1,852 +0,0 @@ -""" -This module contains implementations for the termui module. To keep the -import time of Click down, some infrequently used functionality is -placed in this module and only imported as needed. -""" - -from __future__ import annotations - -import collections.abc as cabc -import contextlib -import math -import os -import shlex -import sys -import time -import typing as t -from gettext import gettext as _ -from io import StringIO -from pathlib import Path -from types import TracebackType - -from ._compat import _default_text_stdout -from ._compat import CYGWIN -from ._compat import get_best_encoding -from ._compat import isatty -from ._compat import open_stream -from ._compat import strip_ansi -from ._compat import term_len -from ._compat import WIN -from .exceptions import ClickException -from .utils import echo - -V = t.TypeVar("V") - -if os.name == "nt": - BEFORE_BAR = "\r" - AFTER_BAR = "\n" -else: - BEFORE_BAR = "\r\033[?25l" - AFTER_BAR = "\033[?25h\n" - - -class ProgressBar(t.Generic[V]): - def __init__( - self, - iterable: cabc.Iterable[V] | None, - length: int | None = None, - fill_char: str = "#", - empty_char: str = " ", - bar_template: str = "%(bar)s", - info_sep: str = " ", - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - item_show_func: t.Callable[[V | None], str | None] | None = None, - label: str | None = None, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, - width: int = 30, - ) -> None: - self.fill_char = fill_char - self.empty_char = empty_char - self.bar_template = bar_template - self.info_sep = info_sep - self.hidden = hidden - self.show_eta = show_eta - self.show_percent = show_percent - self.show_pos = show_pos - self.item_show_func = item_show_func - self.label: str = label or "" - - if file is None: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - file = StringIO() - - self.file = file - self.color = color - self.update_min_steps = update_min_steps - self._completed_intervals = 0 - self.width: int = width - self.autowidth: bool = width == 0 - - if length is None: - from operator import length_hint - - length = length_hint(iterable, -1) - - if length == -1: - length = None - if iterable is None: - if length is None: - raise TypeError("iterable or length is required") - iterable = t.cast("cabc.Iterable[V]", range(length)) - self.iter: cabc.Iterable[V] = iter(iterable) - self.length = length - self.pos: int = 0 - self.avg: list[float] = [] - self.last_eta: float - self.start: float - self.start = self.last_eta = time.time() - self.eta_known: bool = False - self.finished: bool = False - self.max_width: int | None = None - self.entered: bool = False - self.current_item: V | None = None - self._is_atty = isatty(self.file) - self._last_line: str | None = None - - def __enter__(self) -> ProgressBar[V]: - self.entered = True - self.render_progress() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.render_finish() - - def __iter__(self) -> cabc.Iterator[V]: - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - self.render_progress() - return self.generator() - - def __next__(self) -> V: - # Iteration is defined in terms of a generator function, - # returned by iter(self); use that to define next(). This works - # because `self.iter` is an iterable consumed by that generator, - # so it is re-entry safe. Calling `next(self.generator())` - # twice works and does "what you want". - return next(iter(self)) - - def render_finish(self) -> None: - if self.hidden or not self._is_atty: - return - self.file.write(AFTER_BAR) - self.file.flush() - - @property - def pct(self) -> float: - if self.finished: - return 1.0 - return min(self.pos / (float(self.length or 1) or 1), 1.0) - - @property - def time_per_iteration(self) -> float: - if not self.avg: - return 0.0 - return sum(self.avg) / float(len(self.avg)) - - @property - def eta(self) -> float: - if self.length is not None and not self.finished: - return self.time_per_iteration * (self.length - self.pos) - return 0.0 - - def format_eta(self) -> str: - if self.eta_known: - t = int(self.eta) - seconds = t % 60 - t //= 60 - minutes = t % 60 - t //= 60 - hours = t % 24 - t //= 24 - if t > 0: - return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" - else: - return f"{hours:02}:{minutes:02}:{seconds:02}" - return "" - - def format_pos(self) -> str: - pos = str(self.pos) - if self.length is not None: - pos += f"/{self.length}" - return pos - - def format_pct(self) -> str: - return f"{int(self.pct * 100): 4}%"[1:] - - def format_bar(self) -> str: - if self.length is not None: - bar_length = int(self.pct * self.width) - bar = self.fill_char * bar_length - bar += self.empty_char * (self.width - bar_length) - elif self.finished: - bar = self.fill_char * self.width - else: - chars = list(self.empty_char * (self.width or 1)) - if self.time_per_iteration != 0: - chars[ - int( - (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) - * self.width - ) - ] = self.fill_char - bar = "".join(chars) - return bar - - def format_progress_line(self) -> str: - show_percent = self.show_percent - - info_bits = [] - if self.length is not None and show_percent is None: - show_percent = not self.show_pos - - if self.show_pos: - info_bits.append(self.format_pos()) - if show_percent: - info_bits.append(self.format_pct()) - if self.show_eta and self.eta_known and not self.finished: - info_bits.append(self.format_eta()) - if self.item_show_func is not None: - item_info = self.item_show_func(self.current_item) - if item_info is not None: - info_bits.append(item_info) - - return ( - self.bar_template - % { - "label": self.label, - "bar": self.format_bar(), - "info": self.info_sep.join(info_bits), - } - ).rstrip() - - def render_progress(self) -> None: - if self.hidden: - return - - if not self._is_atty: - # Only output the label once if the output is not a TTY. - if self._last_line != self.label: - self._last_line = self.label - echo(self.label, file=self.file, color=self.color) - return - - buf = [] - # Update width in case the terminal has been resized - if self.autowidth: - import shutil - - old_width = self.width - self.width = 0 - clutter_length = term_len(self.format_progress_line()) - new_width = max(0, shutil.get_terminal_size().columns - clutter_length) - if new_width < old_width and self.max_width is not None: - buf.append(BEFORE_BAR) - buf.append(" " * self.max_width) - self.max_width = new_width - self.width = new_width - - clear_width = self.width - if self.max_width is not None: - clear_width = self.max_width - - buf.append(BEFORE_BAR) - line = self.format_progress_line() - line_len = term_len(line) - if self.max_width is None or self.max_width < line_len: - self.max_width = line_len - - buf.append(line) - buf.append(" " * (clear_width - line_len)) - line = "".join(buf) - # Render the line only if it changed. - - if line != self._last_line: - self._last_line = line - echo(line, file=self.file, color=self.color, nl=False) - self.file.flush() - - def make_step(self, n_steps: int) -> None: - self.pos += n_steps - if self.length is not None and self.pos >= self.length: - self.finished = True - - if (time.time() - self.last_eta) < 1.0: - return - - self.last_eta = time.time() - - # self.avg is a rolling list of length <= 7 of steps where steps are - # defined as time elapsed divided by the total progress through - # self.length. - if self.pos: - step = (time.time() - self.start) / self.pos - else: - step = time.time() - self.start - - self.avg = self.avg[-6:] + [step] - - self.eta_known = self.length is not None - - def update(self, n_steps: int, current_item: V | None = None) -> None: - """Update the progress bar by advancing a specified number of - steps, and optionally set the ``current_item`` for this new - position. - - :param n_steps: Number of steps to advance. - :param current_item: Optional item to set as ``current_item`` - for the updated position. - - .. versionchanged:: 8.0 - Added the ``current_item`` optional parameter. - - .. versionchanged:: 8.0 - Only render when the number of steps meets the - ``update_min_steps`` threshold. - """ - if current_item is not None: - self.current_item = current_item - - self._completed_intervals += n_steps - - if self._completed_intervals >= self.update_min_steps: - self.make_step(self._completed_intervals) - self.render_progress() - self._completed_intervals = 0 - - def finish(self) -> None: - self.eta_known = False - self.current_item = None - self.finished = True - - def generator(self) -> cabc.Iterator[V]: - """Return a generator which yields the items added to the bar - during construction, and updates the progress bar *after* the - yielded block returns. - """ - # WARNING: the iterator interface for `ProgressBar` relies on - # this and only works because this is a simple generator which - # doesn't create or manage additional state. If this function - # changes, the impact should be evaluated both against - # `iter(bar)` and `next(bar)`. `next()` in particular may call - # `self.generator()` repeatedly, and this must remain safe in - # order for that interface to work. - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - - if not self._is_atty: - yield from self.iter - else: - for rv in self.iter: - self.current_item = rv - - # This allows show_item_func to be updated before the - # item is processed. Only trigger at the beginning of - # the update interval. - if self._completed_intervals == 0: - self.render_progress() - - yield rv - self.update(1) - - self.finish() - self.render_progress() - - -def pager(generator: cabc.Iterable[str], color: bool | None = None) -> None: - """Decide what method to use for paging through text.""" - stdout = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if stdout is None: - stdout = StringIO() - - if not isatty(sys.stdin) or not isatty(stdout): - return _nullpager(stdout, generator, color) - - # Split and normalize the pager command into parts. - pager_cmd_parts = shlex.split(os.environ.get("PAGER", ""), posix=False) - if pager_cmd_parts: - if WIN: - if _tempfilepager(generator, pager_cmd_parts, color): - return - elif _pipepager(generator, pager_cmd_parts, color): - return - - if os.environ.get("TERM") in ("dumb", "emacs"): - return _nullpager(stdout, generator, color) - if (WIN or sys.platform.startswith("os2")) and _tempfilepager( - generator, ["more"], color - ): - return - if _pipepager(generator, ["less"], color): - return - - import tempfile - - fd, filename = tempfile.mkstemp() - os.close(fd) - try: - if _pipepager(generator, ["more"], color): - return - return _nullpager(stdout, generator, color) - finally: - os.unlink(filename) - - -def _pipepager( - generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None -) -> bool: - """Page through text by feeding it to another program. Invoking a - pager through this might support colors. - - Returns `True` if the command was found, `False` otherwise and thus another - pager should be attempted. - """ - # Split the command into the invoked CLI and its parameters. - if not cmd_parts: - return False - - import shutil - - cmd = cmd_parts[0] - cmd_params = cmd_parts[1:] - - cmd_filepath = shutil.which(cmd) - if not cmd_filepath: - return False - - # Produces a normalized absolute path string. - # multi-call binaries such as busybox derive their identity from the symlink - # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) - cmd_path = Path(cmd_filepath).absolute() - cmd_name = cmd_path.name - - import subprocess - - # Make a local copy of the environment to not affect the global one. - env = dict(os.environ) - - # If we're piping to less and the user hasn't decided on colors, we enable - # them by default we find the -R flag in the command line arguments. - if color is None and cmd_name == "less": - less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_params)}" - if not less_flags: - env["LESS"] = "-R" - color = True - elif "r" in less_flags or "R" in less_flags: - color = True - - c = subprocess.Popen( - [str(cmd_path)] + cmd_params, - shell=False, - stdin=subprocess.PIPE, - env=env, - errors="replace", - text=True, - ) - assert c.stdin is not None - try: - for text in generator: - if not color: - text = strip_ansi(text) - - c.stdin.write(text) - except BrokenPipeError: - # In case the pager exited unexpectedly, ignore the broken pipe error. - pass - except Exception as e: - # In case there is an exception we want to close the pager immediately - # and let the caller handle it. - # Otherwise the pager will keep running, and the user may not notice - # the error message, or worse yet it may leave the terminal in a broken state. - c.terminate() - raise e - finally: - # We must close stdin and wait for the pager to exit before we continue - try: - c.stdin.close() - # Close implies flush, so it might throw a BrokenPipeError if the pager - # process exited already. - except BrokenPipeError: - pass - - # Less doesn't respect ^C, but catches it for its own UI purposes (aborting - # search or other commands inside less). - # - # That means when the user hits ^C, the parent process (click) terminates, - # but less is still alive, paging the output and messing up the terminal. - # - # If the user wants to make the pager exit on ^C, they should set - # `LESS='-K'`. It's not our decision to make. - while True: - try: - c.wait() - except KeyboardInterrupt: - pass - else: - break - - return True - - -def _tempfilepager( - generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None -) -> bool: - """Page through text by invoking a program on a temporary file. - - Returns `True` if the command was found, `False` otherwise and thus another - pager should be attempted. - """ - # Split the command into the invoked CLI and its parameters. - if not cmd_parts: - return False - - import shutil - - cmd = cmd_parts[0] - - cmd_filepath = shutil.which(cmd) - if not cmd_filepath: - return False - # Produces a normalized absolute path string. - # multi-call binaries such as busybox derive their identity from the symlink - # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) - cmd_path = Path(cmd_filepath).absolute() - - import subprocess - import tempfile - - fd, filename = tempfile.mkstemp() - # TODO: This never terminates if the passed generator never terminates. - text = "".join(generator) - if not color: - text = strip_ansi(text) - encoding = get_best_encoding(sys.stdout) - with open_stream(filename, "wb")[0] as f: - f.write(text.encode(encoding)) - try: - subprocess.call([str(cmd_path), filename]) - except OSError: - # Command not found - pass - finally: - os.close(fd) - os.unlink(filename) - - return True - - -def _nullpager( - stream: t.TextIO, generator: cabc.Iterable[str], color: bool | None -) -> None: - """Simply print unformatted text. This is the ultimate fallback.""" - for text in generator: - if not color: - text = strip_ansi(text) - stream.write(text) - - -class Editor: - def __init__( - self, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", - ) -> None: - self.editor = editor - self.env = env - self.require_save = require_save - self.extension = extension - - def get_editor(self) -> str: - if self.editor is not None: - return self.editor - for key in "VISUAL", "EDITOR": - rv = os.environ.get(key) - if rv: - return rv - if WIN: - return "notepad" - - from shutil import which - - for editor in "sensible-editor", "vim", "nano": - if which(editor) is not None: - return editor - return "vi" - - def edit_files(self, filenames: cabc.Iterable[str]) -> None: - import subprocess - - editor = self.get_editor() - environ: dict[str, str] | None = None - - if self.env: - environ = os.environ.copy() - environ.update(self.env) - - exc_filename = " ".join(f'"{filename}"' for filename in filenames) - - try: - c = subprocess.Popen( - args=f"{editor} {exc_filename}", env=environ, shell=True - ) - exit_code = c.wait() - if exit_code != 0: - raise ClickException( - _("{editor}: Editing failed").format(editor=editor) - ) - except OSError as e: - raise ClickException( - _("{editor}: Editing failed: {e}").format(editor=editor, e=e) - ) from e - - @t.overload - def edit(self, text: bytes | bytearray) -> bytes | None: ... - - # We cannot know whether or not the type expected is str or bytes when None - # is passed, so str is returned as that was what was done before. - @t.overload - def edit(self, text: str | None) -> str | None: ... - - def edit(self, text: str | bytes | bytearray | None) -> str | bytes | None: - import tempfile - - if text is None: - data: bytes | bytearray = b"" - elif isinstance(text, (bytes, bytearray)): - data = text - else: - if text and not text.endswith("\n"): - text += "\n" - - if WIN: - data = text.replace("\n", "\r\n").encode("utf-8-sig") - else: - data = text.encode("utf-8") - - fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) - f: t.BinaryIO - - try: - with os.fdopen(fd, "wb") as f: - f.write(data) - - # If the filesystem resolution is 1 second, like Mac OS - # 10.12 Extended, or 2 seconds, like FAT32, and the editor - # closes very fast, require_save can fail. Set the modified - # time to be 2 seconds in the past to work around this. - os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) - # Depending on the resolution, the exact value might not be - # recorded, so get the new recorded value. - timestamp = os.path.getmtime(name) - - self.edit_files((name,)) - - if self.require_save and os.path.getmtime(name) == timestamp: - return None - - with open(name, "rb") as f: - rv = f.read() - - if isinstance(text, (bytes, bytearray)): - return rv - - return rv.decode("utf-8-sig").replace("\r\n", "\n") - finally: - os.unlink(name) - - -def open_url(url: str, wait: bool = False, locate: bool = False) -> int: - import subprocess - - def _unquote_file(url: str) -> str: - from urllib.parse import unquote - - if url.startswith("file://"): - url = unquote(url[7:]) - - return url - - if sys.platform == "darwin": - args = ["open"] - if wait: - args.append("-W") - if locate: - args.append("-R") - args.append(_unquote_file(url)) - null = open("/dev/null", "w") - try: - return subprocess.Popen(args, stderr=null).wait() - finally: - null.close() - elif WIN: - if locate: - url = _unquote_file(url) - args = ["explorer", f"/select,{url}"] - else: - args = ["start"] - if wait: - args.append("/WAIT") - args.append("") - args.append(url) - try: - return subprocess.call(args) - except OSError: - # Command not found - return 127 - elif CYGWIN: - if locate: - url = _unquote_file(url) - args = ["cygstart", os.path.dirname(url)] - else: - args = ["cygstart"] - if wait: - args.append("-w") - args.append(url) - try: - return subprocess.call(args) - except OSError: - # Command not found - return 127 - - try: - if locate: - url = os.path.dirname(_unquote_file(url)) or "." - else: - url = _unquote_file(url) - c = subprocess.Popen(["xdg-open", url]) - if wait: - return c.wait() - return 0 - except OSError: - if url.startswith(("http://", "https://")) and not locate and not wait: - import webbrowser - - webbrowser.open(url) - return 0 - return 1 - - -def _translate_ch_to_exc(ch: str) -> None: - if ch == "\x03": - raise KeyboardInterrupt() - - if ch == "\x04" and not WIN: # Unix-like, Ctrl+D - raise EOFError() - - if ch == "\x1a" and WIN: # Windows, Ctrl+Z - raise EOFError() - - return None - - -if sys.platform == "win32": - import msvcrt - - @contextlib.contextmanager - def raw_terminal() -> cabc.Iterator[int]: - yield -1 - - def getchar(echo: bool) -> str: - # The function `getch` will return a bytes object corresponding to - # the pressed character. Since Windows 10 build 1803, it will also - # return \x00 when called a second time after pressing a regular key. - # - # `getwch` does not share this probably-bugged behavior. Moreover, it - # returns a Unicode object by default, which is what we want. - # - # Either of these functions will return \x00 or \xe0 to indicate - # a special key, and you need to call the same function again to get - # the "rest" of the code. The fun part is that \u00e0 is - # "latin small letter a with grave", so if you type that on a French - # keyboard, you _also_ get a \xe0. - # E.g., consider the Up arrow. This returns \xe0 and then \x48. The - # resulting Unicode string reads as "a with grave" + "capital H". - # This is indistinguishable from when the user actually types - # "a with grave" and then "capital H". - # - # When \xe0 is returned, we assume it's part of a special-key sequence - # and call `getwch` again, but that means that when the user types - # the \u00e0 character, `getchar` doesn't return until a second - # character is typed. - # The alternative is returning immediately, but that would mess up - # cross-platform handling of arrow keys and others that start with - # \xe0. Another option is using `getch`, but then we can't reliably - # read non-ASCII characters, because return values of `getch` are - # limited to the current 8-bit codepage. - # - # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` - # is doing the right thing in more situations than with `getch`. - - if echo: - func = t.cast(t.Callable[[], str], msvcrt.getwche) - else: - func = t.cast(t.Callable[[], str], msvcrt.getwch) - - rv = func() - - if rv in ("\x00", "\xe0"): - # \x00 and \xe0 are control characters that indicate special key, - # see above. - rv += func() - - _translate_ch_to_exc(rv) - return rv - -else: - import termios - import tty - - @contextlib.contextmanager - def raw_terminal() -> cabc.Iterator[int]: - f: t.TextIO | None - fd: int - - if not isatty(sys.stdin): - f = open("/dev/tty") - fd = f.fileno() - else: - fd = sys.stdin.fileno() - f = None - - try: - old_settings = termios.tcgetattr(fd) - - try: - tty.setraw(fd) - yield fd - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - sys.stdout.flush() - - if f is not None: - f.close() - except termios.error: - pass - - def getchar(echo: bool) -> str: - with raw_terminal() as fd: - ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") - - if echo and isatty(sys.stdout): - sys.stdout.write(ch) - - _translate_ch_to_exc(ch) - return ch diff --git a/venv/lib/python3.10/site-packages/click/_textwrap.py b/venv/lib/python3.10/site-packages/click/_textwrap.py deleted file mode 100644 index 97fbee3dc6ce372600e702d38d9139bcf6a40bec..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/_textwrap.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import textwrap -from contextlib import contextmanager - - -class TextWrapper(textwrap.TextWrapper): - def _handle_long_word( - self, - reversed_chunks: list[str], - cur_line: list[str], - cur_len: int, - width: int, - ) -> None: - space_left = max(width - cur_len, 1) - - if self.break_long_words: - last = reversed_chunks[-1] - cut = last[:space_left] - res = last[space_left:] - cur_line.append(cut) - reversed_chunks[-1] = res - elif not cur_line: - cur_line.append(reversed_chunks.pop()) - - @contextmanager - def extra_indent(self, indent: str) -> cabc.Iterator[None]: - old_initial_indent = self.initial_indent - old_subsequent_indent = self.subsequent_indent - self.initial_indent += indent - self.subsequent_indent += indent - - try: - yield - finally: - self.initial_indent = old_initial_indent - self.subsequent_indent = old_subsequent_indent - - def indent_only(self, text: str) -> str: - rv = [] - - for idx, line in enumerate(text.splitlines()): - indent = self.initial_indent - - if idx > 0: - indent = self.subsequent_indent - - rv.append(f"{indent}{line}") - - return "\n".join(rv) diff --git a/venv/lib/python3.10/site-packages/click/_utils.py b/venv/lib/python3.10/site-packages/click/_utils.py deleted file mode 100644 index 09fb00855e68840d18187f3de3a604e7defc37e8..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/_utils.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import annotations - -import enum -import typing as t - - -class Sentinel(enum.Enum): - """Enum used to define sentinel values. - - .. seealso:: - - `PEP 661 - Sentinel Values `_. - """ - - UNSET = object() - FLAG_NEEDS_VALUE = object() - - def __repr__(self) -> str: - return f"{self.__class__.__name__}.{self.name}" - - -UNSET = Sentinel.UNSET -"""Sentinel used to indicate that a value is not set.""" - -FLAG_NEEDS_VALUE = Sentinel.FLAG_NEEDS_VALUE -"""Sentinel used to indicate an option was passed as a flag without a -value but is not a flag option. - -``Option.consume_value`` uses this to prompt or use the ``flag_value``. -""" - -T_UNSET = t.Literal[UNSET] # type: ignore[valid-type] -"""Type hint for the :data:`UNSET` sentinel value.""" - -T_FLAG_NEEDS_VALUE = t.Literal[FLAG_NEEDS_VALUE] # type: ignore[valid-type] -"""Type hint for the :data:`FLAG_NEEDS_VALUE` sentinel value.""" diff --git a/venv/lib/python3.10/site-packages/click/_winconsole.py b/venv/lib/python3.10/site-packages/click/_winconsole.py deleted file mode 100644 index e56c7c6ae7ee7e577db6ace659cd58c0c652074c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/_winconsole.py +++ /dev/null @@ -1,296 +0,0 @@ -# This module is based on the excellent work by Adam Bartoš who -# provided a lot of what went into the implementation here in -# the discussion to issue1602 in the Python bug tracker. -# -# There are some general differences in regards to how this works -# compared to the original patches as we do not need to patch -# the entire interpreter but just work in our little world of -# echo and prompt. -from __future__ import annotations - -import collections.abc as cabc -import io -import sys -import time -import typing as t -from ctypes import Array -from ctypes import byref -from ctypes import c_char -from ctypes import c_char_p -from ctypes import c_int -from ctypes import c_ssize_t -from ctypes import c_ulong -from ctypes import c_void_p -from ctypes import POINTER -from ctypes import py_object -from ctypes import Structure -from ctypes.wintypes import DWORD -from ctypes.wintypes import HANDLE -from ctypes.wintypes import LPCWSTR -from ctypes.wintypes import LPWSTR - -from ._compat import _NonClosingTextIOWrapper - -assert sys.platform == "win32" -import msvcrt # noqa: E402 -from ctypes import windll # noqa: E402 -from ctypes import WINFUNCTYPE # noqa: E402 - -c_ssize_p = POINTER(c_ssize_t) - -kernel32 = windll.kernel32 -GetStdHandle = kernel32.GetStdHandle -ReadConsoleW = kernel32.ReadConsoleW -WriteConsoleW = kernel32.WriteConsoleW -GetConsoleMode = kernel32.GetConsoleMode -GetLastError = kernel32.GetLastError -GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) -CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( - ("CommandLineToArgvW", windll.shell32) -) -LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) - -STDIN_HANDLE = GetStdHandle(-10) -STDOUT_HANDLE = GetStdHandle(-11) -STDERR_HANDLE = GetStdHandle(-12) - -PyBUF_SIMPLE = 0 -PyBUF_WRITABLE = 1 - -ERROR_SUCCESS = 0 -ERROR_NOT_ENOUGH_MEMORY = 8 -ERROR_OPERATION_ABORTED = 995 - -STDIN_FILENO = 0 -STDOUT_FILENO = 1 -STDERR_FILENO = 2 - -EOF = b"\x1a" -MAX_BYTES_WRITTEN = 32767 - -if t.TYPE_CHECKING: - try: - # Using `typing_extensions.Buffer` instead of `collections.abc` - # on Windows for some reason does not have `Sized` implemented. - from collections.abc import Buffer # type: ignore - except ImportError: - from typing_extensions import Buffer - -try: - from ctypes import pythonapi -except ImportError: - # On PyPy we cannot get buffers so our ability to operate here is - # severely limited. - get_buffer = None -else: - - class Py_buffer(Structure): - _fields_ = [ # noqa: RUF012 - ("buf", c_void_p), - ("obj", py_object), - ("len", c_ssize_t), - ("itemsize", c_ssize_t), - ("readonly", c_int), - ("ndim", c_int), - ("format", c_char_p), - ("shape", c_ssize_p), - ("strides", c_ssize_p), - ("suboffsets", c_ssize_p), - ("internal", c_void_p), - ] - - PyObject_GetBuffer = pythonapi.PyObject_GetBuffer - PyBuffer_Release = pythonapi.PyBuffer_Release - - def get_buffer(obj: Buffer, writable: bool = False) -> Array[c_char]: - buf = Py_buffer() - flags: int = PyBUF_WRITABLE if writable else PyBUF_SIMPLE - PyObject_GetBuffer(py_object(obj), byref(buf), flags) - - try: - buffer_type = c_char * buf.len - out: Array[c_char] = buffer_type.from_address(buf.buf) - return out - finally: - PyBuffer_Release(byref(buf)) - - -class _WindowsConsoleRawIOBase(io.RawIOBase): - def __init__(self, handle: int | None) -> None: - self.handle = handle - - def isatty(self) -> t.Literal[True]: - super().isatty() - return True - - -class _WindowsConsoleReader(_WindowsConsoleRawIOBase): - def readable(self) -> t.Literal[True]: - return True - - def readinto(self, b: Buffer) -> int: - bytes_to_be_read = len(b) - if not bytes_to_be_read: - return 0 - elif bytes_to_be_read % 2: - raise ValueError( - "cannot read odd number of bytes from UTF-16-LE encoded console" - ) - - buffer = get_buffer(b, writable=True) - code_units_to_be_read = bytes_to_be_read // 2 - code_units_read = c_ulong() - - rv = ReadConsoleW( - HANDLE(self.handle), - buffer, - code_units_to_be_read, - byref(code_units_read), - None, - ) - if GetLastError() == ERROR_OPERATION_ABORTED: - # wait for KeyboardInterrupt - time.sleep(0.1) - if not rv: - raise OSError(f"Windows error: {GetLastError()}") - - if buffer[0] == EOF: - return 0 - return 2 * code_units_read.value - - -class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): - def writable(self) -> t.Literal[True]: - return True - - @staticmethod - def _get_error_message(errno: int) -> str: - if errno == ERROR_SUCCESS: - return "ERROR_SUCCESS" - elif errno == ERROR_NOT_ENOUGH_MEMORY: - return "ERROR_NOT_ENOUGH_MEMORY" - return f"Windows error {errno}" - - def write(self, b: Buffer) -> int: - bytes_to_be_written = len(b) - buf = get_buffer(b) - code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 - code_units_written = c_ulong() - - WriteConsoleW( - HANDLE(self.handle), - buf, - code_units_to_be_written, - byref(code_units_written), - None, - ) - bytes_written = 2 * code_units_written.value - - if bytes_written == 0 and bytes_to_be_written > 0: - raise OSError(self._get_error_message(GetLastError())) - return bytes_written - - -class ConsoleStream: - def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: - self._text_stream = text_stream - self.buffer = byte_stream - - @property - def name(self) -> str: - return self.buffer.name - - def write(self, x: t.AnyStr) -> int: - if isinstance(x, str): - return self._text_stream.write(x) - try: - self.flush() - except Exception: - pass - return self.buffer.write(x) - - def writelines(self, lines: cabc.Iterable[t.AnyStr]) -> None: - for line in lines: - self.write(line) - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._text_stream, name) - - def isatty(self) -> bool: - return self.buffer.isatty() - - def __repr__(self) -> str: - return f"" - - -def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -_stream_factories: cabc.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { - 0: _get_text_stdin, - 1: _get_text_stdout, - 2: _get_text_stderr, -} - - -def _is_console(f: t.TextIO) -> bool: - if not hasattr(f, "fileno"): - return False - - try: - fileno = f.fileno() - except (OSError, io.UnsupportedOperation): - return False - - handle = msvcrt.get_osfhandle(fileno) - return bool(GetConsoleMode(handle, byref(DWORD()))) - - -def _get_windows_console_stream( - f: t.TextIO, encoding: str | None, errors: str | None -) -> t.TextIO | None: - if ( - get_buffer is None - or encoding not in {"utf-16-le", None} - or errors not in {"strict", None} - or not _is_console(f) - ): - return None - - func = _stream_factories.get(f.fileno()) - if func is None: - return None - - b = getattr(f, "buffer", None) - - if b is None: - return None - - return func(b) diff --git a/venv/lib/python3.10/site-packages/click/core.py b/venv/lib/python3.10/site-packages/click/core.py deleted file mode 100644 index 57f549c7936beb8111d40bc90edd2ac74cacdd8d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/core.py +++ /dev/null @@ -1,3415 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import enum -import errno -import inspect -import os -import sys -import typing as t -from collections import abc -from collections import Counter -from contextlib import AbstractContextManager -from contextlib import contextmanager -from contextlib import ExitStack -from functools import update_wrapper -from gettext import gettext as _ -from gettext import ngettext -from itertools import repeat -from types import TracebackType - -from . import types -from ._utils import FLAG_NEEDS_VALUE -from ._utils import UNSET -from .exceptions import Abort -from .exceptions import BadParameter -from .exceptions import ClickException -from .exceptions import Exit -from .exceptions import MissingParameter -from .exceptions import NoArgsIsHelpError -from .exceptions import UsageError -from .formatting import HelpFormatter -from .formatting import join_options -from .globals import pop_context -from .globals import push_context -from .parser import _OptionParser -from .parser import _split_opt -from .termui import confirm -from .termui import prompt -from .termui import style -from .utils import _detect_program_name -from .utils import _expand_args -from .utils import echo -from .utils import make_default_short_help -from .utils import make_str -from .utils import PacifyFlushWrapper - -if t.TYPE_CHECKING: - from .shell_completion import CompletionItem - -F = t.TypeVar("F", bound="t.Callable[..., t.Any]") -V = t.TypeVar("V") - - -def _complete_visible_commands( - ctx: Context, incomplete: str -) -> cabc.Iterator[tuple[str, Command]]: - """List all the subcommands of a group that start with the - incomplete value and aren't hidden. - - :param ctx: Invocation context for the group. - :param incomplete: Value being completed. May be empty. - """ - multi = t.cast(Group, ctx.command) - - for name in multi.list_commands(ctx): - if name.startswith(incomplete): - command = multi.get_command(ctx, name) - - if command is not None and not command.hidden: - yield name, command - - -def _check_nested_chain( - base_command: Group, cmd_name: str, cmd: Command, register: bool = False -) -> None: - if not base_command.chain or not isinstance(cmd, Group): - return - - if register: - message = ( - f"It is not possible to add the group {cmd_name!r} to another" - f" group {base_command.name!r} that is in chain mode." - ) - else: - message = ( - f"Found the group {cmd_name!r} as subcommand to another group " - f" {base_command.name!r} that is in chain mode. This is not supported." - ) - - raise RuntimeError(message) - - -def batch(iterable: cabc.Iterable[V], batch_size: int) -> list[tuple[V, ...]]: - return list(zip(*repeat(iter(iterable), batch_size), strict=False)) - - -@contextmanager -def augment_usage_errors( - ctx: Context, param: Parameter | None = None -) -> cabc.Iterator[None]: - """Context manager that attaches extra information to exceptions.""" - try: - yield - except BadParameter as e: - if e.ctx is None: - e.ctx = ctx - if param is not None and e.param is None: - e.param = param - raise - except UsageError as e: - if e.ctx is None: - e.ctx = ctx - raise - - -def iter_params_for_processing( - invocation_order: cabc.Sequence[Parameter], - declaration_order: cabc.Sequence[Parameter], -) -> list[Parameter]: - """Returns all declared parameters in the order they should be processed. - - The declared parameters are re-shuffled depending on the order in which - they were invoked, as well as the eagerness of each parameters. - - The invocation order takes precedence over the declaration order. I.e. the - order in which the user provided them to the CLI is respected. - - This behavior and its effect on callback evaluation is detailed at: - https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order - """ - - def sort_key(item: Parameter) -> tuple[bool, float]: - try: - idx: float = invocation_order.index(item) - except ValueError: - idx = float("inf") - - return not item.is_eager, idx - - return sorted(declaration_order, key=sort_key) - - -class ParameterSource(enum.Enum): - """This is an :class:`~enum.Enum` that indicates the source of a - parameter's value. - - Use :meth:`click.Context.get_parameter_source` to get the - source for a parameter by name. - - .. versionchanged:: 8.0 - Use :class:`~enum.Enum` and drop the ``validate`` method. - - .. versionchanged:: 8.0 - Added the ``PROMPT`` value. - """ - - COMMANDLINE = enum.auto() - """The value was provided by the command line args.""" - ENVIRONMENT = enum.auto() - """The value was provided with an environment variable.""" - DEFAULT = enum.auto() - """Used the default specified by the parameter.""" - DEFAULT_MAP = enum.auto() - """Used a default provided by :attr:`Context.default_map`.""" - PROMPT = enum.auto() - """Used a prompt to confirm a default or provide a value.""" - - -class Context: - """The context is a special internal object that holds state relevant - for the script execution at every single level. It's normally invisible - to commands unless they opt-in to getting access to it. - - The context is useful as it can pass internal objects around and can - control special execution features such as reading data from - environment variables. - - A context can be used as context manager in which case it will call - :meth:`close` on teardown. - - :param command: the command class for this context. - :param parent: the parent context. - :param info_name: the info name for this invocation. Generally this - is the most descriptive name for the script or - command. For the toplevel script it is usually - the name of the script, for commands below it it's - the name of the script. - :param obj: an arbitrary object of user data. - :param auto_envvar_prefix: the prefix to use for automatic environment - variables. If this is `None` then reading - from environment variables is disabled. This - does not affect manually set environment - variables which are always read. - :param default_map: a dictionary (like object) with default values - for parameters. - :param terminal_width: the width of the terminal. The default is - inherit from parent context. If no context - defines the terminal width then auto - detection will be applied. - :param max_content_width: the maximum width for content rendered by - Click (this currently only affects help - pages). This defaults to 80 characters if - not overridden. In other words: even if the - terminal is larger than that, Click will not - format things wider than 80 characters by - default. In addition to that, formatters might - add some safety mapping on the right. - :param resilient_parsing: if this flag is enabled then Click will - parse without any interactivity or callback - invocation. Default values will also be - ignored. This is useful for implementing - things such as completion support. - :param allow_extra_args: if this is set to `True` then extra arguments - at the end will not raise an error and will be - kept on the context. The default is to inherit - from the command. - :param allow_interspersed_args: if this is set to `False` then options - and arguments cannot be mixed. The - default is to inherit from the command. - :param ignore_unknown_options: instructs click to ignore options it does - not know and keeps them for later - processing. - :param help_option_names: optionally a list of strings that define how - the default help parameter is named. The - default is ``['--help']``. - :param token_normalize_func: an optional function that is used to - normalize tokens (options, choices, - etc.). This for instance can be used to - implement case insensitive behavior. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are used in texts that Click prints which is by - default not the case. This for instance would affect - help output. - :param show_default: Show the default value for commands. If this - value is not set, it defaults to the value from the parent - context. ``Command.show_default`` overrides this default for the - specific command. - - .. versionchanged:: 8.2 - The ``protected_args`` attribute is deprecated and will be removed in - Click 9.0. ``args`` will contain remaining unparsed tokens. - - .. versionchanged:: 8.1 - The ``show_default`` parameter is overridden by - ``Command.show_default``, instead of the other way around. - - .. versionchanged:: 8.0 - The ``show_default`` parameter defaults to the value from the - parent context. - - .. versionchanged:: 7.1 - Added the ``show_default`` parameter. - - .. versionchanged:: 4.0 - Added the ``color``, ``ignore_unknown_options``, and - ``max_content_width`` parameters. - - .. versionchanged:: 3.0 - Added the ``allow_extra_args`` and ``allow_interspersed_args`` - parameters. - - .. versionchanged:: 2.0 - Added the ``resilient_parsing``, ``help_option_names``, and - ``token_normalize_func`` parameters. - """ - - #: The formatter class to create with :meth:`make_formatter`. - #: - #: .. versionadded:: 8.0 - formatter_class: type[HelpFormatter] = HelpFormatter - - def __init__( - self, - command: Command, - parent: Context | None = None, - info_name: str | None = None, - obj: t.Any | None = None, - auto_envvar_prefix: str | None = None, - default_map: cabc.MutableMapping[str, t.Any] | None = None, - terminal_width: int | None = None, - max_content_width: int | None = None, - resilient_parsing: bool = False, - allow_extra_args: bool | None = None, - allow_interspersed_args: bool | None = None, - ignore_unknown_options: bool | None = None, - help_option_names: list[str] | None = None, - token_normalize_func: t.Callable[[str], str] | None = None, - color: bool | None = None, - show_default: bool | None = None, - ) -> None: - #: the parent context or `None` if none exists. - self.parent = parent - #: the :class:`Command` for this context. - self.command = command - #: the descriptive information name - self.info_name = info_name - #: Map of parameter names to their parsed values. Parameters - #: with ``expose_value=False`` are not stored. - self.params: dict[str, t.Any] = {} - #: the leftover arguments. - self.args: list[str] = [] - #: protected arguments. These are arguments that are prepended - #: to `args` when certain parsing scenarios are encountered but - #: must be never propagated to another arguments. This is used - #: to implement nested parsing. - self._protected_args: list[str] = [] - #: the collected prefixes of the command's options. - self._opt_prefixes: set[str] = set(parent._opt_prefixes) if parent else set() - - if obj is None and parent is not None: - obj = parent.obj - - #: the user object stored. - self.obj: t.Any = obj - self._meta: dict[str, t.Any] = getattr(parent, "meta", {}) - - #: A dictionary (-like object) with defaults for parameters. - if ( - default_map is None - and info_name is not None - and parent is not None - and parent.default_map is not None - ): - default_map = parent.default_map.get(info_name) - - self.default_map: cabc.MutableMapping[str, t.Any] | None = default_map - - #: This flag indicates if a subcommand is going to be executed. A - #: group callback can use this information to figure out if it's - #: being executed directly or because the execution flow passes - #: onwards to a subcommand. By default it's None, but it can be - #: the name of the subcommand to execute. - #: - #: If chaining is enabled this will be set to ``'*'`` in case - #: any commands are executed. It is however not possible to - #: figure out which ones. If you require this knowledge you - #: should use a :func:`result_callback`. - self.invoked_subcommand: str | None = None - - if terminal_width is None and parent is not None: - terminal_width = parent.terminal_width - - #: The width of the terminal (None is autodetection). - self.terminal_width: int | None = terminal_width - - if max_content_width is None and parent is not None: - max_content_width = parent.max_content_width - - #: The maximum width of formatted content (None implies a sensible - #: default which is 80 for most things). - self.max_content_width: int | None = max_content_width - - if allow_extra_args is None: - allow_extra_args = command.allow_extra_args - - #: Indicates if the context allows extra args or if it should - #: fail on parsing. - #: - #: .. versionadded:: 3.0 - self.allow_extra_args = allow_extra_args - - if allow_interspersed_args is None: - allow_interspersed_args = command.allow_interspersed_args - - #: Indicates if the context allows mixing of arguments and - #: options or not. - #: - #: .. versionadded:: 3.0 - self.allow_interspersed_args: bool = allow_interspersed_args - - if ignore_unknown_options is None: - ignore_unknown_options = command.ignore_unknown_options - - #: Instructs click to ignore options that a command does not - #: understand and will store it on the context for later - #: processing. This is primarily useful for situations where you - #: want to call into external programs. Generally this pattern is - #: strongly discouraged because it's not possibly to losslessly - #: forward all arguments. - #: - #: .. versionadded:: 4.0 - self.ignore_unknown_options: bool = ignore_unknown_options - - if help_option_names is None: - if parent is not None: - help_option_names = parent.help_option_names - else: - help_option_names = ["--help"] - - #: The names for the help options. - self.help_option_names: list[str] = help_option_names - - if token_normalize_func is None and parent is not None: - token_normalize_func = parent.token_normalize_func - - #: An optional normalization function for tokens. This is - #: options, choices, commands etc. - self.token_normalize_func: t.Callable[[str], str] | None = token_normalize_func - - #: Indicates if resilient parsing is enabled. In that case Click - #: will do its best to not cause any failures and default values - #: will be ignored. Useful for completion. - self.resilient_parsing: bool = resilient_parsing - - # If there is no envvar prefix yet, but the parent has one and - # the command on this level has a name, we can expand the envvar - # prefix automatically. - if auto_envvar_prefix is None: - if ( - parent is not None - and parent.auto_envvar_prefix is not None - and self.info_name is not None - ): - auto_envvar_prefix = ( - f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" - ) - else: - auto_envvar_prefix = auto_envvar_prefix.upper() - - if auto_envvar_prefix is not None: - auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") - - self.auto_envvar_prefix: str | None = auto_envvar_prefix - - if color is None and parent is not None: - color = parent.color - - #: Controls if styling output is wanted or not. - self.color: bool | None = color - - if show_default is None and parent is not None: - show_default = parent.show_default - - #: Show option default values when formatting help text. - self.show_default: bool | None = show_default - - self._close_callbacks: list[t.Callable[[], t.Any]] = [] - self._depth = 0 - self._parameter_source: dict[str, ParameterSource] = {} - self._exit_stack = ExitStack() - - @property - def protected_args(self) -> list[str]: - import warnings - - warnings.warn( - "'protected_args' is deprecated and will be removed in Click 9.0." - " 'args' will contain remaining unparsed tokens.", - DeprecationWarning, - stacklevel=2, - ) - return self._protected_args - - def to_info_dict(self) -> dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. This traverses the entire CLI - structure. - - .. code-block:: python - - with Context(cli) as ctx: - info = ctx.to_info_dict() - - .. versionadded:: 8.0 - """ - return { - "command": self.command.to_info_dict(self), - "info_name": self.info_name, - "allow_extra_args": self.allow_extra_args, - "allow_interspersed_args": self.allow_interspersed_args, - "ignore_unknown_options": self.ignore_unknown_options, - "auto_envvar_prefix": self.auto_envvar_prefix, - } - - def __enter__(self) -> Context: - self._depth += 1 - push_context(self) - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> bool | None: - self._depth -= 1 - exit_result: bool | None = None - if self._depth == 0: - exit_result = self._close_with_exception_info(exc_type, exc_value, tb) - pop_context() - - return exit_result - - @contextmanager - def scope(self, cleanup: bool = True) -> cabc.Iterator[Context]: - """This helper method can be used with the context object to promote - it to the current thread local (see :func:`get_current_context`). - The default behavior of this is to invoke the cleanup functions which - can be disabled by setting `cleanup` to `False`. The cleanup - functions are typically used for things such as closing file handles. - - If the cleanup is intended the context object can also be directly - used as a context manager. - - Example usage:: - - with ctx.scope(): - assert get_current_context() is ctx - - This is equivalent:: - - with ctx: - assert get_current_context() is ctx - - .. versionadded:: 5.0 - - :param cleanup: controls if the cleanup functions should be run or - not. The default is to run these functions. In - some situations the context only wants to be - temporarily pushed in which case this can be disabled. - Nested pushes automatically defer the cleanup. - """ - if not cleanup: - self._depth += 1 - try: - with self as rv: - yield rv - finally: - if not cleanup: - self._depth -= 1 - - @property - def meta(self) -> dict[str, t.Any]: - """This is a dictionary which is shared with all the contexts - that are nested. It exists so that click utilities can store some - state here if they need to. It is however the responsibility of - that code to manage this dictionary well. - - The keys are supposed to be unique dotted strings. For instance - module paths are a good choice for it. What is stored in there is - irrelevant for the operation of click. However what is important is - that code that places data here adheres to the general semantics of - the system. - - Example usage:: - - LANG_KEY = f'{__name__}.lang' - - def set_language(value): - ctx = get_current_context() - ctx.meta[LANG_KEY] = value - - def get_language(): - return get_current_context().meta.get(LANG_KEY, 'en_US') - - .. versionadded:: 5.0 - """ - return self._meta - - def make_formatter(self) -> HelpFormatter: - """Creates the :class:`~click.HelpFormatter` for the help and - usage output. - - To quickly customize the formatter class used without overriding - this method, set the :attr:`formatter_class` attribute. - - .. versionchanged:: 8.0 - Added the :attr:`formatter_class` attribute. - """ - return self.formatter_class( - width=self.terminal_width, max_width=self.max_content_width - ) - - def with_resource(self, context_manager: AbstractContextManager[V]) -> V: - """Register a resource as if it were used in a ``with`` - statement. The resource will be cleaned up when the context is - popped. - - Uses :meth:`contextlib.ExitStack.enter_context`. It calls the - resource's ``__enter__()`` method and returns the result. When - the context is popped, it closes the stack, which calls the - resource's ``__exit__()`` method. - - To register a cleanup function for something that isn't a - context manager, use :meth:`call_on_close`. Or use something - from :mod:`contextlib` to turn it into a context manager first. - - .. code-block:: python - - @click.group() - @click.option("--name") - @click.pass_context - def cli(ctx): - ctx.obj = ctx.with_resource(connect_db(name)) - - :param context_manager: The context manager to enter. - :return: Whatever ``context_manager.__enter__()`` returns. - - .. versionadded:: 8.0 - """ - return self._exit_stack.enter_context(context_manager) - - def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: - """Register a function to be called when the context tears down. - - This can be used to close resources opened during the script - execution. Resources that support Python's context manager - protocol which would be used in a ``with`` statement should be - registered with :meth:`with_resource` instead. - - :param f: The function to execute on teardown. - """ - return self._exit_stack.callback(f) - - def close(self) -> None: - """Invoke all close callbacks registered with - :meth:`call_on_close`, and exit all context managers entered - with :meth:`with_resource`. - """ - self._close_with_exception_info(None, None, None) - - def _close_with_exception_info( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> bool | None: - """Unwind the exit stack by calling its :meth:`__exit__` providing the exception - information to allow for exception handling by the various resources registered - using :meth;`with_resource` - - :return: Whatever ``exit_stack.__exit__()`` returns. - """ - exit_result = self._exit_stack.__exit__(exc_type, exc_value, tb) - # In case the context is reused, create a new exit stack. - self._exit_stack = ExitStack() - - return exit_result - - @property - def command_path(self) -> str: - """The computed command path. This is used for the ``usage`` - information on the help page. It's automatically created by - combining the info names of the chain of contexts to the root. - """ - rv = "" - if self.info_name is not None: - rv = self.info_name - if self.parent is not None: - parent_command_path = [self.parent.command_path] - - if isinstance(self.parent.command, Command): - for param in self.parent.command.get_params(self): - parent_command_path.extend(param.get_usage_pieces(self)) - - rv = f"{' '.join(parent_command_path)} {rv}" - return rv.lstrip() - - def find_root(self) -> Context: - """Finds the outermost context.""" - node = self - while node.parent is not None: - node = node.parent - return node - - def find_object(self, object_type: type[V]) -> V | None: - """Finds the closest object of a given type.""" - node: Context | None = self - - while node is not None: - if isinstance(node.obj, object_type): - return node.obj - - node = node.parent - - return None - - def ensure_object(self, object_type: type[V]) -> V: - """Like :meth:`find_object` but sets the innermost object to a - new instance of `object_type` if it does not exist. - """ - rv = self.find_object(object_type) - if rv is None: - self.obj = rv = object_type() - return rv - - @t.overload - def lookup_default( - self, name: str, call: t.Literal[True] = True - ) -> t.Any | None: ... - - @t.overload - def lookup_default( - self, name: str, call: t.Literal[False] = ... - ) -> t.Any | t.Callable[[], t.Any] | None: ... - - def lookup_default(self, name: str, call: bool = True) -> t.Any | None: - """Get the default for a parameter from :attr:`default_map`. - - :param name: Name of the parameter. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - if self.default_map is not None: - value = self.default_map.get(name, UNSET) - - if call and callable(value): - return value() - - return value - - return UNSET - - def fail(self, message: str) -> t.NoReturn: - """Aborts the execution of the program with a specific error - message. - - :param message: the error message to fail with. - """ - raise UsageError(message, self) - - def abort(self) -> t.NoReturn: - """Aborts the script.""" - raise Abort() - - def exit(self, code: int = 0) -> t.NoReturn: - """Exits the application with a given exit code. - - .. versionchanged:: 8.2 - Callbacks and context managers registered with :meth:`call_on_close` - and :meth:`with_resource` are closed before exiting. - """ - self.close() - raise Exit(code) - - def get_usage(self) -> str: - """Helper method to get formatted usage string for the current - context and command. - """ - return self.command.get_usage(self) - - def get_help(self) -> str: - """Helper method to get formatted help page for the current - context and command. - """ - return self.command.get_help(self) - - def _make_sub_context(self, command: Command) -> Context: - """Create a new context of the same type as this context, but - for a new command. - - :meta private: - """ - return type(self)(command, info_name=command.name, parent=self) - - @t.overload - def invoke( - self, callback: t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any - ) -> V: ... - - @t.overload - def invoke(self, callback: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: ... - - def invoke( - self, callback: Command | t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any - ) -> t.Any | V: - """Invokes a command callback in exactly the way it expects. There - are two ways to invoke this method: - - 1. the first argument can be a callback and all other arguments and - keyword arguments are forwarded directly to the function. - 2. the first argument is a click command object. In that case all - arguments are forwarded as well but proper click parameters - (options and click arguments) must be keyword arguments and Click - will fill in defaults. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if :meth:`forward` is called at multiple levels. - - .. versionchanged:: 3.2 - A new context is created, and missing arguments use default values. - """ - if isinstance(callback, Command): - other_cmd = callback - - if other_cmd.callback is None: - raise TypeError( - "The given command does not have a callback that can be invoked." - ) - else: - callback = t.cast("t.Callable[..., V]", other_cmd.callback) - - ctx = self._make_sub_context(other_cmd) - - for param in other_cmd.params: - if param.name not in kwargs and param.expose_value: - default_value = param.get_default(ctx) - # We explicitly hide the :attr:`UNSET` value to the user, as we - # choose to make it an implementation detail. And because ``invoke`` - # has been designed as part of Click public API, we return ``None`` - # instead. Refs: - # https://github.com/pallets/click/issues/3066 - # https://github.com/pallets/click/issues/3065 - # https://github.com/pallets/click/pull/3068 - if default_value is UNSET: - default_value = None - kwargs[param.name] = param.type_cast_value( # type: ignore - ctx, default_value - ) - - # Track all kwargs as params, so that forward() will pass - # them on in subsequent calls. - ctx.params.update(kwargs) - else: - ctx = self - - with augment_usage_errors(self): - with ctx: - return callback(*args, **kwargs) - - def forward(self, cmd: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: - """Similar to :meth:`invoke` but fills in default keyword - arguments from the current context if the other command expects - it. This cannot invoke callbacks directly, only other commands. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if ``forward`` is called at multiple levels. - """ - # Can only forward to other commands, not direct callbacks. - if not isinstance(cmd, Command): - raise TypeError("Callback is not a command.") - - for param in self.params: - if param not in kwargs: - kwargs[param] = self.params[param] - - return self.invoke(cmd, *args, **kwargs) - - def set_parameter_source(self, name: str, source: ParameterSource) -> None: - """Set the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - :param name: The name of the parameter. - :param source: A member of :class:`~click.core.ParameterSource`. - """ - self._parameter_source[name] = source - - def get_parameter_source(self, name: str) -> ParameterSource | None: - """Get the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - This can be useful for determining when a user specified a value - on the command line that is the same as the default value. It - will be :attr:`~click.core.ParameterSource.DEFAULT` only if the - value was actually taken from the default. - - :param name: The name of the parameter. - :rtype: ParameterSource - - .. versionchanged:: 8.0 - Returns ``None`` if the parameter was not provided from any - source. - """ - return self._parameter_source.get(name) - - -class Command: - """Commands are the basic building block of command line interfaces in - Click. A basic command handles command line parsing and might dispatch - more parsing to commands nested below it. - - :param name: the name of the command to use unless a group overrides it. - :param context_settings: an optional dictionary with defaults that are - passed to the context object. - :param callback: the callback to invoke. This is optional. - :param params: the parameters to register with this command. This can - be either :class:`Option` or :class:`Argument` objects. - :param help: the help string to use for this command. - :param epilog: like the help string but it's printed at the end of the - help page after everything else. - :param short_help: the short help to use for this command. This is - shown on the command listing of the parent command. - :param add_help_option: by default each command registers a ``--help`` - option. This can be disabled by this parameter. - :param no_args_is_help: this controls what happens if no arguments are - provided. This option is disabled by default. - If enabled this will add ``--help`` as argument - if no arguments are passed - :param hidden: hide this command from help outputs. - :param deprecated: If ``True`` or non-empty string, issues a message - indicating that the command is deprecated and highlights - its deprecation in --help. The message can be customized - by using a string as the value. - - .. versionchanged:: 8.2 - This is the base class for all commands, not ``BaseCommand``. - ``deprecated`` can be set to a string as well to customize the - deprecation message. - - .. versionchanged:: 8.1 - ``help``, ``epilog``, and ``short_help`` are stored unprocessed, - all formatting is done when outputting help text, not at init, - and is done even if not using the ``@command`` decorator. - - .. versionchanged:: 8.0 - Added a ``repr`` showing the command name. - - .. versionchanged:: 7.1 - Added the ``no_args_is_help`` parameter. - - .. versionchanged:: 2.0 - Added the ``context_settings`` parameter. - """ - - #: The context class to create with :meth:`make_context`. - #: - #: .. versionadded:: 8.0 - context_class: type[Context] = Context - - #: the default for the :attr:`Context.allow_extra_args` flag. - allow_extra_args = False - - #: the default for the :attr:`Context.allow_interspersed_args` flag. - allow_interspersed_args = True - - #: the default for the :attr:`Context.ignore_unknown_options` flag. - ignore_unknown_options = False - - def __init__( - self, - name: str | None, - context_settings: cabc.MutableMapping[str, t.Any] | None = None, - callback: t.Callable[..., t.Any] | None = None, - params: list[Parameter] | None = None, - help: str | None = None, - epilog: str | None = None, - short_help: str | None = None, - options_metavar: str | None = "[OPTIONS]", - add_help_option: bool = True, - no_args_is_help: bool = False, - hidden: bool = False, - deprecated: bool | str = False, - ) -> None: - #: the name the command thinks it has. Upon registering a command - #: on a :class:`Group` the group will default the command name - #: with this information. You should instead use the - #: :class:`Context`\'s :attr:`~Context.info_name` attribute. - self.name = name - - if context_settings is None: - context_settings = {} - - #: an optional dictionary with defaults passed to the context. - self.context_settings: cabc.MutableMapping[str, t.Any] = context_settings - - #: the callback to execute when the command fires. This might be - #: `None` in which case nothing happens. - self.callback = callback - #: the list of parameters for this command in the order they - #: should show up in the help page and execute. Eager parameters - #: will automatically be handled before non eager ones. - self.params: list[Parameter] = params or [] - self.help = help - self.epilog = epilog - self.options_metavar = options_metavar - self.short_help = short_help - self.add_help_option = add_help_option - self._help_option = None - self.no_args_is_help = no_args_is_help - self.hidden = hidden - self.deprecated = deprecated - - def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: - return { - "name": self.name, - "params": [param.to_info_dict() for param in self.get_params(ctx)], - "help": self.help, - "epilog": self.epilog, - "short_help": self.short_help, - "hidden": self.hidden, - "deprecated": self.deprecated, - } - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - def get_usage(self, ctx: Context) -> str: - """Formats the usage line into a string and returns it. - - Calls :meth:`format_usage` internally. - """ - formatter = ctx.make_formatter() - self.format_usage(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_params(self, ctx: Context) -> list[Parameter]: - params = self.params - help_option = self.get_help_option(ctx) - - if help_option is not None: - params = [*params, help_option] - - if __debug__: - import warnings - - opts = [opt for param in params for opt in param.opts] - opts_counter = Counter(opts) - duplicate_opts = (opt for opt, count in opts_counter.items() if count > 1) - - for duplicate_opt in duplicate_opts: - warnings.warn( - ( - f"The parameter {duplicate_opt} is used more than once. " - "Remove its duplicate as parameters should be unique." - ), - stacklevel=3, - ) - - return params - - def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the usage line into the formatter. - - This is a low-level method called by :meth:`get_usage`. - """ - pieces = self.collect_usage_pieces(ctx) - formatter.write_usage(ctx.command_path, " ".join(pieces)) - - def collect_usage_pieces(self, ctx: Context) -> list[str]: - """Returns all the pieces that go into the usage line and returns - it as a list of strings. - """ - rv = [self.options_metavar] if self.options_metavar else [] - - for param in self.get_params(ctx): - rv.extend(param.get_usage_pieces(ctx)) - - return rv - - def get_help_option_names(self, ctx: Context) -> list[str]: - """Returns the names for the help option.""" - all_names = set(ctx.help_option_names) - for param in self.params: - all_names.difference_update(param.opts) - all_names.difference_update(param.secondary_opts) - return list(all_names) - - def get_help_option(self, ctx: Context) -> Option | None: - """Returns the help option object. - - Skipped if :attr:`add_help_option` is ``False``. - - .. versionchanged:: 8.1.8 - The help option is now cached to avoid creating it multiple times. - """ - help_option_names = self.get_help_option_names(ctx) - - if not help_option_names or not self.add_help_option: - return None - - # Cache the help option object in private _help_option attribute to - # avoid creating it multiple times. Not doing this will break the - # callback odering by iter_params_for_processing(), which relies on - # object comparison. - if self._help_option is None: - # Avoid circular import. - from .decorators import help_option - - # Apply help_option decorator and pop resulting option - help_option(*help_option_names)(self) - self._help_option = self.params.pop() # type: ignore[assignment] - - return self._help_option - - def make_parser(self, ctx: Context) -> _OptionParser: - """Creates the underlying option parser for this command.""" - parser = _OptionParser(ctx) - for param in self.get_params(ctx): - param.add_to_parser(parser, ctx) - return parser - - def get_help(self, ctx: Context) -> str: - """Formats the help into a string and returns it. - - Calls :meth:`format_help` internally. - """ - formatter = ctx.make_formatter() - self.format_help(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_short_help_str(self, limit: int = 45) -> str: - """Gets short help for the command or makes it by shortening the - long help string. - """ - if self.short_help: - text = inspect.cleandoc(self.short_help) - elif self.help: - text = make_default_short_help(self.help, limit) - else: - text = "" - - if self.deprecated: - deprecated_message = ( - f"(DEPRECATED: {self.deprecated})" - if isinstance(self.deprecated, str) - else "(DEPRECATED)" - ) - text = _("{text} {deprecated_message}").format( - text=text, deprecated_message=deprecated_message - ) - - return text.strip() - - def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help into the formatter if it exists. - - This is a low-level method called by :meth:`get_help`. - - This calls the following methods: - - - :meth:`format_usage` - - :meth:`format_help_text` - - :meth:`format_options` - - :meth:`format_epilog` - """ - self.format_usage(ctx, formatter) - self.format_help_text(ctx, formatter) - self.format_options(ctx, formatter) - self.format_epilog(ctx, formatter) - - def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help text to the formatter if it exists.""" - if self.help is not None: - # truncate the help text to the first form feed - text = inspect.cleandoc(self.help).partition("\f")[0] - else: - text = "" - - if self.deprecated: - deprecated_message = ( - f"(DEPRECATED: {self.deprecated})" - if isinstance(self.deprecated, str) - else "(DEPRECATED)" - ) - text = _("{text} {deprecated_message}").format( - text=text, deprecated_message=deprecated_message - ) - - if text: - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(text) - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes all the options into the formatter if they exist.""" - opts = [] - for param in self.get_params(ctx): - rv = param.get_help_record(ctx) - if rv is not None: - opts.append(rv) - - if opts: - with formatter.section(_("Options")): - formatter.write_dl(opts) - - def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the epilog into the formatter if it exists.""" - if self.epilog: - epilog = inspect.cleandoc(self.epilog) - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(epilog) - - def make_context( - self, - info_name: str | None, - args: list[str], - parent: Context | None = None, - **extra: t.Any, - ) -> Context: - """This function when given an info name and arguments will kick - off the parsing and create a new :class:`Context`. It does not - invoke the actual command callback though. - - To quickly customize the context class used without overriding - this method, set the :attr:`context_class` attribute. - - :param info_name: the info name for this invocation. Generally this - is the most descriptive name for the script or - command. For the toplevel script it's usually - the name of the script, for commands below it's - the name of the command. - :param args: the arguments to parse as list of strings. - :param parent: the parent context if available. - :param extra: extra keyword arguments forwarded to the context - constructor. - - .. versionchanged:: 8.0 - Added the :attr:`context_class` attribute. - """ - for key, value in self.context_settings.items(): - if key not in extra: - extra[key] = value - - ctx = self.context_class(self, info_name=info_name, parent=parent, **extra) - - with ctx.scope(cleanup=False): - self.parse_args(ctx, args) - return ctx - - def parse_args(self, ctx: Context, args: list[str]) -> list[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - raise NoArgsIsHelpError(ctx) - - parser = self.make_parser(ctx) - opts, args, param_order = parser.parse_args(args=args) - - for param in iter_params_for_processing(param_order, self.get_params(ctx)): - _, args = param.handle_parse_result(ctx, opts, args) - - # We now have all parameters' values into `ctx.params`, but the data may contain - # the `UNSET` sentinel. - # Convert `UNSET` to `None` to ensure that the user doesn't see `UNSET`. - # - # Waiting until after the initial parse to convert allows us to treat `UNSET` - # more like a missing value when multiple params use the same name. - # Refs: - # https://github.com/pallets/click/issues/3071 - # https://github.com/pallets/click/pull/3079 - for name, value in ctx.params.items(): - if value is UNSET: - ctx.params[name] = None - - if args and not ctx.allow_extra_args and not ctx.resilient_parsing: - ctx.fail( - ngettext( - "Got unexpected extra argument ({args})", - "Got unexpected extra arguments ({args})", - len(args), - ).format(args=" ".join(map(str, args))) - ) - - ctx.args = args - ctx._opt_prefixes.update(parser._opt_prefixes) - return args - - def invoke(self, ctx: Context) -> t.Any: - """Given a context, this invokes the attached callback (if it exists) - in the right way. - """ - if self.deprecated: - extra_message = ( - f" {self.deprecated}" if isinstance(self.deprecated, str) else "" - ) - message = _( - "DeprecationWarning: The command {name!r} is deprecated.{extra_message}" - ).format(name=self.name, extra_message=extra_message) - echo(style(message, fg="red"), err=True) - - if self.callback is not None: - return ctx.invoke(self.callback, **ctx.params) - - def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: - """Return a list of completions for the incomplete value. Looks - at the names of options and chained multi-commands. - - Any command could be part of a chained multi-command, so sibling - commands are valid at any point during command completion. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results: list[CompletionItem] = [] - - if incomplete and not incomplete[0].isalnum(): - for param in self.get_params(ctx): - if ( - not isinstance(param, Option) - or param.hidden - or ( - not param.multiple - and ctx.get_parameter_source(param.name) # type: ignore - is ParameterSource.COMMANDLINE - ) - ): - continue - - results.extend( - CompletionItem(name, help=param.help) - for name in [*param.opts, *param.secondary_opts] - if name.startswith(incomplete) - ) - - while ctx.parent is not None: - ctx = ctx.parent - - if isinstance(ctx.command, Group) and ctx.command.chain: - results.extend( - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - if name not in ctx._protected_args - ) - - return results - - @t.overload - def main( - self, - args: cabc.Sequence[str] | None = None, - prog_name: str | None = None, - complete_var: str | None = None, - standalone_mode: t.Literal[True] = True, - **extra: t.Any, - ) -> t.NoReturn: ... - - @t.overload - def main( - self, - args: cabc.Sequence[str] | None = None, - prog_name: str | None = None, - complete_var: str | None = None, - standalone_mode: bool = ..., - **extra: t.Any, - ) -> t.Any: ... - - def main( - self, - args: cabc.Sequence[str] | None = None, - prog_name: str | None = None, - complete_var: str | None = None, - standalone_mode: bool = True, - windows_expand_args: bool = True, - **extra: t.Any, - ) -> t.Any: - """This is the way to invoke a script with all the bells and - whistles as a command line application. This will always terminate - the application after a call. If this is not wanted, ``SystemExit`` - needs to be caught. - - This method is also available by directly calling the instance of - a :class:`Command`. - - :param args: the arguments that should be used for parsing. If not - provided, ``sys.argv[1:]`` is used. - :param prog_name: the program name that should be used. By default - the program name is constructed by taking the file - name from ``sys.argv[0]``. - :param complete_var: the environment variable that controls the - bash completion support. The default is - ``"__COMPLETE"`` with prog_name in - uppercase. - :param standalone_mode: the default behavior is to invoke the script - in standalone mode. Click will then - handle exceptions and convert them into - error messages and the function will never - return but shut down the interpreter. If - this is set to `False` they will be - propagated to the caller and the return - value of this function is the return value - of :meth:`invoke`. - :param windows_expand_args: Expand glob patterns, user dir, and - env vars in command line args on Windows. - :param extra: extra keyword arguments are forwarded to the context - constructor. See :class:`Context` for more information. - - .. versionchanged:: 8.0.1 - Added the ``windows_expand_args`` parameter to allow - disabling command line arg expansion on Windows. - - .. versionchanged:: 8.0 - When taking arguments from ``sys.argv`` on Windows, glob - patterns, user dir, and env vars are expanded. - - .. versionchanged:: 3.0 - Added the ``standalone_mode`` parameter. - """ - if args is None: - args = sys.argv[1:] - - if os.name == "nt" and windows_expand_args: - args = _expand_args(args) - else: - args = list(args) - - if prog_name is None: - prog_name = _detect_program_name() - - # Process shell completion requests and exit early. - self._main_shell_completion(extra, prog_name, complete_var) - - try: - try: - with self.make_context(prog_name, args, **extra) as ctx: - rv = self.invoke(ctx) - if not standalone_mode: - return rv - # it's not safe to `ctx.exit(rv)` here! - # note that `rv` may actually contain data like "1" which - # has obvious effects - # more subtle case: `rv=[None, None]` can come out of - # chained commands which all returned `None` -- so it's not - # even always obvious that `rv` indicates success/failure - # by its truthiness/falsiness - ctx.exit() - except (EOFError, KeyboardInterrupt) as e: - echo(file=sys.stderr) - raise Abort() from e - except ClickException as e: - if not standalone_mode: - raise - e.show() - sys.exit(e.exit_code) - except OSError as e: - if e.errno == errno.EPIPE: - sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) - sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) - sys.exit(1) - else: - raise - except Exit as e: - if standalone_mode: - sys.exit(e.exit_code) - else: - # in non-standalone mode, return the exit code - # note that this is only reached if `self.invoke` above raises - # an Exit explicitly -- thus bypassing the check there which - # would return its result - # the results of non-standalone execution may therefore be - # somewhat ambiguous: if there are codepaths which lead to - # `ctx.exit(1)` and to `return 1`, the caller won't be able to - # tell the difference between the two - return e.exit_code - except Abort: - if not standalone_mode: - raise - echo(_("Aborted!"), file=sys.stderr) - sys.exit(1) - - def _main_shell_completion( - self, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str | None = None, - ) -> None: - """Check if the shell is asking for tab completion, process - that, then exit early. Called from :meth:`main` before the - program is invoked. - - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. Defaults to - ``_{PROG_NAME}_COMPLETE``. - - .. versionchanged:: 8.2.0 - Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). - """ - if complete_var is None: - complete_name = prog_name.replace("-", "_").replace(".", "_") - complete_var = f"_{complete_name}_COMPLETE".upper() - - instruction = os.environ.get(complete_var) - - if not instruction: - return - - from .shell_completion import shell_complete - - rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) - sys.exit(rv) - - def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: - """Alias for :meth:`main`.""" - return self.main(*args, **kwargs) - - -class _FakeSubclassCheck(type): - def __subclasscheck__(cls, subclass: type) -> bool: - return issubclass(subclass, cls.__bases__[0]) - - def __instancecheck__(cls, instance: t.Any) -> bool: - return isinstance(instance, cls.__bases__[0]) - - -class _BaseCommand(Command, metaclass=_FakeSubclassCheck): - """ - .. deprecated:: 8.2 - Will be removed in Click 9.0. Use ``Command`` instead. - """ - - -class Group(Command): - """A group is a command that nests other commands (or more groups). - - :param name: The name of the group command. - :param commands: Map names to :class:`Command` objects. Can be a list, which - will use :attr:`Command.name` as the keys. - :param invoke_without_command: Invoke the group's callback even if a - subcommand is not given. - :param no_args_is_help: If no arguments are given, show the group's help and - exit. Defaults to the opposite of ``invoke_without_command``. - :param subcommand_metavar: How to represent the subcommand argument in help. - The default will represent whether ``chain`` is set or not. - :param chain: Allow passing more than one subcommand argument. After parsing - a command's arguments, if any arguments remain another command will be - matched, and so on. - :param result_callback: A function to call after the group's and - subcommand's callbacks. The value returned by the subcommand is passed. - If ``chain`` is enabled, the value will be a list of values returned by - all the commands. If ``invoke_without_command`` is enabled, the value - will be the value returned by the group's callback, or an empty list if - ``chain`` is enabled. - :param kwargs: Other arguments passed to :class:`Command`. - - .. versionchanged:: 8.0 - The ``commands`` argument can be a list of command objects. - - .. versionchanged:: 8.2 - Merged with and replaces the ``MultiCommand`` base class. - """ - - allow_extra_args = True - allow_interspersed_args = False - - #: If set, this is used by the group's :meth:`command` decorator - #: as the default :class:`Command` class. This is useful to make all - #: subcommands use a custom command class. - #: - #: .. versionadded:: 8.0 - command_class: type[Command] | None = None - - #: If set, this is used by the group's :meth:`group` decorator - #: as the default :class:`Group` class. This is useful to make all - #: subgroups use a custom group class. - #: - #: If set to the special value :class:`type` (literally - #: ``group_class = type``), this group's class will be used as the - #: default class. This makes a custom group class continue to make - #: custom groups. - #: - #: .. versionadded:: 8.0 - group_class: type[Group] | type[type] | None = None - # Literal[type] isn't valid, so use Type[type] - - def __init__( - self, - name: str | None = None, - commands: cabc.MutableMapping[str, Command] - | cabc.Sequence[Command] - | None = None, - invoke_without_command: bool = False, - no_args_is_help: bool | None = None, - subcommand_metavar: str | None = None, - chain: bool = False, - result_callback: t.Callable[..., t.Any] | None = None, - **kwargs: t.Any, - ) -> None: - super().__init__(name, **kwargs) - - if commands is None: - commands = {} - elif isinstance(commands, abc.Sequence): - commands = {c.name: c for c in commands if c.name is not None} - - #: The registered subcommands by their exported names. - self.commands: cabc.MutableMapping[str, Command] = commands - - if no_args_is_help is None: - no_args_is_help = not invoke_without_command - - self.no_args_is_help = no_args_is_help - self.invoke_without_command = invoke_without_command - - if subcommand_metavar is None: - if chain: - subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." - else: - subcommand_metavar = "COMMAND [ARGS]..." - - self.subcommand_metavar = subcommand_metavar - self.chain = chain - # The result callback that is stored. This can be set or - # overridden with the :func:`result_callback` decorator. - self._result_callback = result_callback - - if self.chain: - for param in self.params: - if isinstance(param, Argument) and not param.required: - raise RuntimeError( - "A group in chain mode cannot have optional arguments." - ) - - def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: - info_dict = super().to_info_dict(ctx) - commands = {} - - for name in self.list_commands(ctx): - command = self.get_command(ctx, name) - - if command is None: - continue - - sub_ctx = ctx._make_sub_context(command) - - with sub_ctx.scope(cleanup=False): - commands[name] = command.to_info_dict(sub_ctx) - - info_dict.update(commands=commands, chain=self.chain) - return info_dict - - def add_command(self, cmd: Command, name: str | None = None) -> None: - """Registers another :class:`Command` with this group. If the name - is not provided, the name of the command is used. - """ - name = name or cmd.name - if name is None: - raise TypeError("Command has no name.") - _check_nested_chain(self, name, cmd, register=True) - self.commands[name] = cmd - - @t.overload - def command(self, __func: t.Callable[..., t.Any]) -> Command: ... - - @t.overload - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... - - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Command] | Command: - """A shortcut decorator for declaring and attaching a command to - the group. This takes the same arguments as :func:`command` and - immediately registers the created command with this group by - calling :meth:`add_command`. - - To customize the command class used, set the - :attr:`command_class` attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`command_class` attribute. - """ - from .decorators import command - - func: t.Callable[..., t.Any] | None = None - - if args and callable(args[0]): - assert len(args) == 1 and not kwargs, ( - "Use 'command(**kwargs)(callable)' to provide arguments." - ) - (func,) = args - args = () - - if self.command_class and kwargs.get("cls") is None: - kwargs["cls"] = self.command_class - - def decorator(f: t.Callable[..., t.Any]) -> Command: - cmd: Command = command(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - @t.overload - def group(self, __func: t.Callable[..., t.Any]) -> Group: ... - - @t.overload - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Group]: ... - - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Group] | Group: - """A shortcut decorator for declaring and attaching a group to - the group. This takes the same arguments as :func:`group` and - immediately registers the created group with this group by - calling :meth:`add_command`. - - To customize the group class used, set the :attr:`group_class` - attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`group_class` attribute. - """ - from .decorators import group - - func: t.Callable[..., t.Any] | None = None - - if args and callable(args[0]): - assert len(args) == 1 and not kwargs, ( - "Use 'group(**kwargs)(callable)' to provide arguments." - ) - (func,) = args - args = () - - if self.group_class is not None and kwargs.get("cls") is None: - if self.group_class is type: - kwargs["cls"] = type(self) - else: - kwargs["cls"] = self.group_class - - def decorator(f: t.Callable[..., t.Any]) -> Group: - cmd: Group = group(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: - """Adds a result callback to the command. By default if a - result callback is already registered this will chain them but - this can be disabled with the `replace` parameter. The result - callback is invoked with the return value of the subcommand - (or the list of return values from all subcommands if chaining - is enabled) as well as the parameters as they would be passed - to the main callback. - - Example:: - - @click.group() - @click.option('-i', '--input', default=23) - def cli(input): - return 42 - - @cli.result_callback() - def process_result(result, input): - return result + input - - :param replace: if set to `True` an already existing result - callback will be removed. - - .. versionchanged:: 8.0 - Renamed from ``resultcallback``. - - .. versionadded:: 3.0 - """ - - def decorator(f: F) -> F: - old_callback = self._result_callback - - if old_callback is None or replace: - self._result_callback = f - return f - - def function(value: t.Any, /, *args: t.Any, **kwargs: t.Any) -> t.Any: - inner = old_callback(value, *args, **kwargs) - return f(inner, *args, **kwargs) - - self._result_callback = rv = update_wrapper(t.cast(F, function), f) - return rv # type: ignore[return-value] - - return decorator - - def get_command(self, ctx: Context, cmd_name: str) -> Command | None: - """Given a context and a command name, this returns a :class:`Command` - object if it exists or returns ``None``. - """ - return self.commands.get(cmd_name) - - def list_commands(self, ctx: Context) -> list[str]: - """Returns a list of subcommand names in the order they should appear.""" - return sorted(self.commands) - - def collect_usage_pieces(self, ctx: Context) -> list[str]: - rv = super().collect_usage_pieces(ctx) - rv.append(self.subcommand_metavar) - return rv - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - super().format_options(ctx, formatter) - self.format_commands(ctx, formatter) - - def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: - """Extra format methods for multi methods that adds all the commands - after the options. - """ - commands = [] - for subcommand in self.list_commands(ctx): - cmd = self.get_command(ctx, subcommand) - # What is this, the tool lied about a command. Ignore it - if cmd is None: - continue - if cmd.hidden: - continue - - commands.append((subcommand, cmd)) - - # allow for 3 times the default spacing - if len(commands): - limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) - - rows = [] - for subcommand, cmd in commands: - help = cmd.get_short_help_str(limit) - rows.append((subcommand, help)) - - if rows: - with formatter.section(_("Commands")): - formatter.write_dl(rows) - - def parse_args(self, ctx: Context, args: list[str]) -> list[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - raise NoArgsIsHelpError(ctx) - - rest = super().parse_args(ctx, args) - - if self.chain: - ctx._protected_args = rest - ctx.args = [] - elif rest: - ctx._protected_args, ctx.args = rest[:1], rest[1:] - - return ctx.args - - def invoke(self, ctx: Context) -> t.Any: - def _process_result(value: t.Any) -> t.Any: - if self._result_callback is not None: - value = ctx.invoke(self._result_callback, value, **ctx.params) - return value - - if not ctx._protected_args: - if self.invoke_without_command: - # No subcommand was invoked, so the result callback is - # invoked with the group return value for regular - # groups, or an empty list for chained groups. - with ctx: - rv = super().invoke(ctx) - return _process_result([] if self.chain else rv) - ctx.fail(_("Missing command.")) - - # Fetch args back out - args = [*ctx._protected_args, *ctx.args] - ctx.args = [] - ctx._protected_args = [] - - # If we're not in chain mode, we only allow the invocation of a - # single command but we also inform the current context about the - # name of the command to invoke. - if not self.chain: - # Make sure the context is entered so we do not clean up - # resources until the result processor has worked. - with ctx: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - ctx.invoked_subcommand = cmd_name - super().invoke(ctx) - sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) - with sub_ctx: - return _process_result(sub_ctx.command.invoke(sub_ctx)) - - # In chain mode we create the contexts step by step, but after the - # base command has been invoked. Because at that point we do not - # know the subcommands yet, the invoked subcommand attribute is - # set to ``*`` to inform the command that subcommands are executed - # but nothing else. - with ctx: - ctx.invoked_subcommand = "*" if args else None - super().invoke(ctx) - - # Otherwise we make every single context and invoke them in a - # chain. In that case the return value to the result processor - # is the list of all invoked subcommand's results. - contexts = [] - while args: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - sub_ctx = cmd.make_context( - cmd_name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - ) - contexts.append(sub_ctx) - args, sub_ctx.args = sub_ctx.args, [] - - rv = [] - for sub_ctx in contexts: - with sub_ctx: - rv.append(sub_ctx.command.invoke(sub_ctx)) - return _process_result(rv) - - def resolve_command( - self, ctx: Context, args: list[str] - ) -> tuple[str | None, Command | None, list[str]]: - cmd_name = make_str(args[0]) - original_cmd_name = cmd_name - - # Get the command - cmd = self.get_command(ctx, cmd_name) - - # If we can't find the command but there is a normalization - # function available, we try with that one. - if cmd is None and ctx.token_normalize_func is not None: - cmd_name = ctx.token_normalize_func(cmd_name) - cmd = self.get_command(ctx, cmd_name) - - # If we don't find the command we want to show an error message - # to the user that it was not provided. However, there is - # something else we should do: if the first argument looks like - # an option we want to kick off parsing again for arguments to - # resolve things like --help which now should go to the main - # place. - if cmd is None and not ctx.resilient_parsing: - if _split_opt(cmd_name)[0]: - self.parse_args(ctx, args) - ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) - return cmd_name if cmd else None, cmd, args[1:] - - def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: - """Return a list of completions for the incomplete value. Looks - at the names of options, subcommands, and chained - multi-commands. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results = [ - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - ] - results.extend(super().shell_complete(ctx, incomplete)) - return results - - -class _MultiCommand(Group, metaclass=_FakeSubclassCheck): - """ - .. deprecated:: 8.2 - Will be removed in Click 9.0. Use ``Group`` instead. - """ - - -class CommandCollection(Group): - """A :class:`Group` that looks up subcommands on other groups. If a command - is not found on this group, each registered source is checked in order. - Parameters on a source are not added to this group, and a source's callback - is not invoked when invoking its commands. In other words, this "flattens" - commands in many groups into this one group. - - :param name: The name of the group command. - :param sources: A list of :class:`Group` objects to look up commands from. - :param kwargs: Other arguments passed to :class:`Group`. - - .. versionchanged:: 8.2 - This is a subclass of ``Group``. Commands are looked up first on this - group, then each of its sources. - """ - - def __init__( - self, - name: str | None = None, - sources: list[Group] | None = None, - **kwargs: t.Any, - ) -> None: - super().__init__(name, **kwargs) - #: The list of registered groups. - self.sources: list[Group] = sources or [] - - def add_source(self, group: Group) -> None: - """Add a group as a source of commands.""" - self.sources.append(group) - - def get_command(self, ctx: Context, cmd_name: str) -> Command | None: - rv = super().get_command(ctx, cmd_name) - - if rv is not None: - return rv - - for source in self.sources: - rv = source.get_command(ctx, cmd_name) - - if rv is not None: - if self.chain: - _check_nested_chain(self, cmd_name, rv) - - return rv - - return None - - def list_commands(self, ctx: Context) -> list[str]: - rv: set[str] = set(super().list_commands(ctx)) - - for source in self.sources: - rv.update(source.list_commands(ctx)) - - return sorted(rv) - - -def _check_iter(value: t.Any) -> cabc.Iterator[t.Any]: - """Check if the value is iterable but not a string. Raises a type - error, or return an iterator over the value. - """ - if isinstance(value, str): - raise TypeError - - return iter(value) - - -class Parameter: - r"""A parameter to a command comes in two versions: they are either - :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently - not supported by design as some of the internals for parsing are - intentionally not finalized. - - Some settings are supported by both options and arguments. - - :param param_decls: the parameter declarations for this option or - argument. This is a list of flags or argument - names. - :param type: the type that should be used. Either a :class:`ParamType` - or a Python type. The latter is converted into the former - automatically if supported. - :param required: controls if this is optional or not. - :param default: the default value if omitted. This can also be a callable, - in which case it's invoked when the default is needed - without any arguments. - :param callback: A function to further process or validate the value - after type conversion. It is called as ``f(ctx, param, value)`` - and must return the value. It is called for all sources, - including prompts. - :param nargs: the number of arguments to match. If not ``1`` the return - value is a tuple instead of single value. The default for - nargs is ``1`` (except if the type is a tuple, then it's - the arity of the tuple). If ``nargs=-1``, all remaining - parameters are collected. - :param metavar: how the value is represented in the help page. - :param expose_value: if this is `True` then the value is passed onwards - to the command callback and stored on the context, - otherwise it's skipped. - :param is_eager: eager values are processed before non eager ones. This - should not be set for arguments or it will inverse the - order of processing. - :param envvar: environment variable(s) that are used to provide a default value for - this parameter. This can be a string or a sequence of strings. If a sequence is - given, only the first non-empty environment variable is used for the parameter. - :param shell_complete: A function that returns custom shell - completions. Used instead of the param's type completion if - given. Takes ``ctx, param, incomplete`` and must return a list - of :class:`~click.shell_completion.CompletionItem` or a list of - strings. - :param deprecated: If ``True`` or non-empty string, issues a message - indicating that the argument is deprecated and highlights - its deprecation in --help. The message can be customized - by using a string as the value. A deprecated parameter - cannot be required, a ValueError will be raised otherwise. - - .. versionchanged:: 8.2.0 - Introduction of ``deprecated``. - - .. versionchanged:: 8.2 - Adding duplicate parameter names to a :class:`~click.core.Command` will - result in a ``UserWarning`` being shown. - - .. versionchanged:: 8.2 - Adding duplicate parameter names to a :class:`~click.core.Command` will - result in a ``UserWarning`` being shown. - - .. versionchanged:: 8.0 - ``process_value`` validates required parameters and bounded - ``nargs``, and invokes the parameter callback before returning - the value. This allows the callback to validate prompts. - ``full_process_value`` is removed. - - .. versionchanged:: 8.0 - ``autocompletion`` is renamed to ``shell_complete`` and has new - semantics described above. The old name is deprecated and will - be removed in 8.1, until then it will be wrapped to match the - new requirements. - - .. versionchanged:: 8.0 - For ``multiple=True, nargs>1``, the default must be a list of - tuples. - - .. versionchanged:: 8.0 - Setting a default is no longer required for ``nargs>1``, it will - default to ``None``. ``multiple=True`` or ``nargs=-1`` will - default to ``()``. - - .. versionchanged:: 7.1 - Empty environment variables are ignored rather than taking the - empty string value. This makes it possible for scripts to clear - variables if they can't unset them. - - .. versionchanged:: 2.0 - Changed signature for parameter callback to also be passed the - parameter. The old callback format will still work, but it will - raise a warning to give you a chance to migrate the code easier. - """ - - param_type_name = "parameter" - - def __init__( - self, - param_decls: cabc.Sequence[str] | None = None, - type: types.ParamType | t.Any | None = None, - required: bool = False, - # XXX The default historically embed two concepts: - # - the declaration of a Parameter object carrying the default (handy to - # arbitrage the default value of coupled Parameters sharing the same - # self.name, like flag options), - # - and the actual value of the default. - # It is confusing and is the source of many issues discussed in: - # https://github.com/pallets/click/pull/3030 - # In the future, we might think of splitting it in two, not unlike - # Option.is_flag and Option.flag_value: we could have something like - # Parameter.is_default and Parameter.default_value. - default: t.Any | t.Callable[[], t.Any] | None = UNSET, - callback: t.Callable[[Context, Parameter, t.Any], t.Any] | None = None, - nargs: int | None = None, - multiple: bool = False, - metavar: str | None = None, - expose_value: bool = True, - is_eager: bool = False, - envvar: str | cabc.Sequence[str] | None = None, - shell_complete: t.Callable[ - [Context, Parameter, str], list[CompletionItem] | list[str] - ] - | None = None, - deprecated: bool | str = False, - ) -> None: - self.name: str | None - self.opts: list[str] - self.secondary_opts: list[str] - self.name, self.opts, self.secondary_opts = self._parse_decls( - param_decls or (), expose_value - ) - self.type: types.ParamType = types.convert_type(type, default) - - # Default nargs to what the type tells us if we have that - # information available. - if nargs is None: - if self.type.is_composite: - nargs = self.type.arity - else: - nargs = 1 - - self.required = required - self.callback = callback - self.nargs = nargs - self.multiple = multiple - self.expose_value = expose_value - self.default: t.Any | t.Callable[[], t.Any] | None = default - self.is_eager = is_eager - self.metavar = metavar - self.envvar = envvar - self._custom_shell_complete = shell_complete - self.deprecated = deprecated - - if __debug__: - if self.type.is_composite and nargs != self.type.arity: - raise ValueError( - f"'nargs' must be {self.type.arity} (or None) for" - f" type {self.type!r}, but it was {nargs}." - ) - - if required and deprecated: - raise ValueError( - f"The {self.param_type_name} '{self.human_readable_name}' " - "is deprecated and still required. A deprecated " - f"{self.param_type_name} cannot be required." - ) - - def to_info_dict(self) -> dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionchanged:: 8.3.0 - Returns ``None`` for the :attr:`default` if it was not set. - - .. versionadded:: 8.0 - """ - return { - "name": self.name, - "param_type_name": self.param_type_name, - "opts": self.opts, - "secondary_opts": self.secondary_opts, - "type": self.type.to_info_dict(), - "required": self.required, - "nargs": self.nargs, - "multiple": self.multiple, - # We explicitly hide the :attr:`UNSET` value to the user, as we choose to - # make it an implementation detail. And because ``to_info_dict`` has been - # designed for documentation purposes, we return ``None`` instead. - "default": self.default if self.default is not UNSET else None, - "envvar": self.envvar, - } - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - def _parse_decls( - self, decls: cabc.Sequence[str], expose_value: bool - ) -> tuple[str | None, list[str], list[str]]: - raise NotImplementedError() - - @property - def human_readable_name(self) -> str: - """Returns the human readable name of this parameter. This is the - same as the name for options, but the metavar for arguments. - """ - return self.name # type: ignore - - def make_metavar(self, ctx: Context) -> str: - if self.metavar is not None: - return self.metavar - - metavar = self.type.get_metavar(param=self, ctx=ctx) - - if metavar is None: - metavar = self.type.name.upper() - - if self.nargs != 1: - metavar += "..." - - return metavar - - @t.overload - def get_default( - self, ctx: Context, call: t.Literal[True] = True - ) -> t.Any | None: ... - - @t.overload - def get_default( - self, ctx: Context, call: bool = ... - ) -> t.Any | t.Callable[[], t.Any] | None: ... - - def get_default( - self, ctx: Context, call: bool = True - ) -> t.Any | t.Callable[[], t.Any] | None: - """Get the default for the parameter. Tries - :meth:`Context.lookup_default` first, then the local default. - - :param ctx: Current context. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0.2 - Type casting is no longer performed when getting a default. - - .. versionchanged:: 8.0.1 - Type casting can fail in resilient parsing mode. Invalid - defaults will not prevent showing help text. - - .. versionchanged:: 8.0 - Looks at ``ctx.default_map`` first. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - value = ctx.lookup_default(self.name, call=False) # type: ignore - - if value is UNSET: - value = self.default - - if call and callable(value): - value = value() - - return value - - def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: - raise NotImplementedError() - - def consume_value( - self, ctx: Context, opts: cabc.Mapping[str, t.Any] - ) -> tuple[t.Any, ParameterSource]: - """Returns the parameter value produced by the parser. - - If the parser did not produce a value from user input, the value is either - sourced from the environment variable, the default map, or the parameter's - default value. In that order of precedence. - - If no value is found, an internal sentinel value is returned. - - :meta private: - """ - # Collect from the parse the value passed by the user to the CLI. - value = opts.get(self.name, UNSET) # type: ignore - # If the value is set, it means it was sourced from the command line by the - # parser, otherwise it left unset by default. - source = ( - ParameterSource.COMMANDLINE - if value is not UNSET - else ParameterSource.DEFAULT - ) - - if value is UNSET: - envvar_value = self.value_from_envvar(ctx) - if envvar_value is not None: - value = envvar_value - source = ParameterSource.ENVIRONMENT - - if value is UNSET: - default_map_value = ctx.lookup_default(self.name) # type: ignore - if default_map_value is not UNSET: - value = default_map_value - source = ParameterSource.DEFAULT_MAP - - if value is UNSET: - default_value = self.get_default(ctx) - if default_value is not UNSET: - value = default_value - source = ParameterSource.DEFAULT - - return value, source - - def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: - """Convert and validate a value against the parameter's - :attr:`type`, :attr:`multiple`, and :attr:`nargs`. - """ - if value is None: - if self.multiple or self.nargs == -1: - return () - else: - return value - - def check_iter(value: t.Any) -> cabc.Iterator[t.Any]: - try: - return _check_iter(value) - except TypeError: - # This should only happen when passing in args manually, - # the parser should construct an iterable when parsing - # the command line. - raise BadParameter( - _("Value must be an iterable."), ctx=ctx, param=self - ) from None - - # Define the conversion function based on nargs and type. - - if self.nargs == 1 or self.type.is_composite: - - def convert(value: t.Any) -> t.Any: - return self.type(value, param=self, ctx=ctx) - - elif self.nargs == -1: - - def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] - return tuple(self.type(x, self, ctx) for x in check_iter(value)) - - else: # nargs > 1 - - def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] - value = tuple(check_iter(value)) - - if len(value) != self.nargs: - raise BadParameter( - ngettext( - "Takes {nargs} values but 1 was given.", - "Takes {nargs} values but {len} were given.", - len(value), - ).format(nargs=self.nargs, len=len(value)), - ctx=ctx, - param=self, - ) - - return tuple(self.type(x, self, ctx) for x in value) - - if self.multiple: - return tuple(convert(x) for x in check_iter(value)) - - return convert(value) - - def value_is_missing(self, value: t.Any) -> bool: - """A value is considered missing if: - - - it is :attr:`UNSET`, - - or if it is an empty sequence while the parameter is suppose to have - non-single value (i.e. :attr:`nargs` is not ``1`` or :attr:`multiple` is - set). - - :meta private: - """ - if value is UNSET: - return True - - if (self.nargs != 1 or self.multiple) and value == (): - return True - - return False - - def process_value(self, ctx: Context, value: t.Any) -> t.Any: - """Process the value of this parameter: - - 1. Type cast the value using :meth:`type_cast_value`. - 2. Check if the value is missing (see: :meth:`value_is_missing`), and raise - :exc:`MissingParameter` if it is required. - 3. If a :attr:`callback` is set, call it to have the value replaced by the - result of the callback. If the value was not set, the callback receive - ``None``. This keep the legacy behavior as it was before the introduction of - the :attr:`UNSET` sentinel. - - :meta private: - """ - # shelter `type_cast_value` from ever seeing an `UNSET` value by handling the - # cases in which `UNSET` gets special treatment explicitly at this layer - # - # Refs: - # https://github.com/pallets/click/issues/3069 - if value is UNSET: - if self.multiple or self.nargs == -1: - value = () - else: - value = self.type_cast_value(ctx, value) - - if self.required and self.value_is_missing(value): - raise MissingParameter(ctx=ctx, param=self) - - if self.callback is not None: - # Legacy case: UNSET is not exposed directly to the callback, but converted - # to None. - if value is UNSET: - value = None - - # Search for parameters with UNSET values in the context. - unset_keys = {k: None for k, v in ctx.params.items() if v is UNSET} - # No UNSET values, call the callback as usual. - if not unset_keys: - value = self.callback(ctx, self, value) - - # Legacy case: provide a temporarily manipulated context to the callback - # to hide UNSET values as None. - # - # Refs: - # https://github.com/pallets/click/issues/3136 - # https://github.com/pallets/click/pull/3137 - else: - # Add another layer to the context stack to clearly hint that the - # context is temporarily modified. - with ctx: - # Update the context parameters to replace UNSET with None. - ctx.params.update(unset_keys) - # Feed these fake context parameters to the callback. - value = self.callback(ctx, self, value) - # Restore the UNSET values in the context parameters. - ctx.params.update( - { - k: UNSET - for k in unset_keys - # Only restore keys that are present and still None, in case - # the callback modified other parameters. - if k in ctx.params and ctx.params[k] is None - } - ) - - return value - - def resolve_envvar_value(self, ctx: Context) -> str | None: - """Returns the value found in the environment variable(s) attached to this - parameter. - - Environment variables values are `always returned as strings - `_. - - This method returns ``None`` if: - - - the :attr:`envvar` property is not set on the :class:`Parameter`, - - the environment variable is not found in the environment, - - the variable is found in the environment but its value is empty (i.e. the - environment variable is present but has an empty string). - - If :attr:`envvar` is setup with multiple environment variables, - then only the first non-empty value is returned. - - .. caution:: - - The raw value extracted from the environment is not normalized and is - returned as-is. Any normalization or reconciliation is performed later by - the :class:`Parameter`'s :attr:`type`. - - :meta private: - """ - if not self.envvar: - return None - - if isinstance(self.envvar, str): - rv = os.environ.get(self.envvar) - - if rv: - return rv - else: - for envvar in self.envvar: - rv = os.environ.get(envvar) - - # Return the first non-empty value of the list of environment variables. - if rv: - return rv - # Else, absence of value is interpreted as an environment variable that - # is not set, so proceed to the next one. - - return None - - def value_from_envvar(self, ctx: Context) -> str | cabc.Sequence[str] | None: - """Process the raw environment variable string for this parameter. - - Returns the string as-is or splits it into a sequence of strings if the - parameter is expecting multiple values (i.e. its :attr:`nargs` property is set - to a value other than ``1``). - - :meta private: - """ - rv = self.resolve_envvar_value(ctx) - - if rv is not None and self.nargs != 1: - return self.type.split_envvar_value(rv) - - return rv - - def handle_parse_result( - self, ctx: Context, opts: cabc.Mapping[str, t.Any], args: list[str] - ) -> tuple[t.Any, list[str]]: - """Process the value produced by the parser from user input. - - Always process the value through the Parameter's :attr:`type`, wherever it - comes from. - - If the parameter is deprecated, this method warn the user about it. But only if - the value has been explicitly set by the user (and as such, is not coming from - a default). - - :meta private: - """ - with augment_usage_errors(ctx, param=self): - value, source = self.consume_value(ctx, opts) - - ctx.set_parameter_source(self.name, source) # type: ignore - - # Display a deprecation warning if necessary. - if ( - self.deprecated - and value is not UNSET - and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) - ): - extra_message = ( - f" {self.deprecated}" if isinstance(self.deprecated, str) else "" - ) - message = _( - "DeprecationWarning: The {param_type} {name!r} is deprecated." - "{extra_message}" - ).format( - param_type=self.param_type_name, - name=self.human_readable_name, - extra_message=extra_message, - ) - echo(style(message, fg="red"), err=True) - - # Process the value through the parameter's type. - try: - value = self.process_value(ctx, value) - except Exception: - if not ctx.resilient_parsing: - raise - # In resilient parsing mode, we do not want to fail the command if the - # value is incompatible with the parameter type, so we reset the value - # to UNSET, which will be interpreted as a missing value. - value = UNSET - - # Add parameter's value to the context. - if ( - self.expose_value - # We skip adding the value if it was previously set by another parameter - # targeting the same variable name. This prevents parameters competing for - # the same name to override each other. - and (self.name not in ctx.params or ctx.params[self.name] is UNSET) - ): - # Click is logically enforcing that the name is None if the parameter is - # not to be exposed. We still assert it here to please the type checker. - assert self.name is not None, ( - f"{self!r} parameter's name should not be None when exposing value." - ) - ctx.params[self.name] = value - - return value, args - - def get_help_record(self, ctx: Context) -> tuple[str, str] | None: - pass - - def get_usage_pieces(self, ctx: Context) -> list[str]: - return [] - - def get_error_hint(self, ctx: Context) -> str: - """Get a stringified version of the param for use in error messages to - indicate which param caused the error. - """ - hint_list = self.opts or [self.human_readable_name] - return " / ".join(f"'{x}'" for x in hint_list) - - def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: - """Return a list of completions for the incomplete value. If a - ``shell_complete`` function was given during init, it is used. - Otherwise, the :attr:`type` - :meth:`~click.types.ParamType.shell_complete` function is used. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - if self._custom_shell_complete is not None: - results = self._custom_shell_complete(ctx, self, incomplete) - - if results and isinstance(results[0], str): - from click.shell_completion import CompletionItem - - results = [CompletionItem(c) for c in results] - - return t.cast("list[CompletionItem]", results) - - return self.type.shell_complete(ctx, self, incomplete) - - -class Option(Parameter): - """Options are usually optional values on the command line and - have some extra features that arguments don't have. - - All other parameters are passed onwards to the parameter constructor. - - :param show_default: Show the default value for this option in its - help text. Values are not shown by default, unless - :attr:`Context.show_default` is ``True``. If this value is a - string, it shows that string in parentheses instead of the - actual value. This is particularly useful for dynamic options. - For single option boolean flags, the default remains hidden if - its value is ``False``. - :param show_envvar: Controls if an environment variable should be - shown on the help page and error messages. - Normally, environment variables are not shown. - :param prompt: If set to ``True`` or a non empty string then the - user will be prompted for input. If set to ``True`` the prompt - will be the option name capitalized. A deprecated option cannot be - prompted. - :param confirmation_prompt: Prompt a second time to confirm the - value if it was prompted for. Can be set to a string instead of - ``True`` to customize the message. - :param prompt_required: If set to ``False``, the user will be - prompted for input only when the option was specified as a flag - without a value. - :param hide_input: If this is ``True`` then the input on the prompt - will be hidden from the user. This is useful for password input. - :param is_flag: forces this option to act as a flag. The default is - auto detection. - :param flag_value: which value should be used for this flag if it's - enabled. This is set to a boolean automatically if - the option string contains a slash to mark two options. - :param multiple: if this is set to `True` then the argument is accepted - multiple times and recorded. This is similar to ``nargs`` - in how it works but supports arbitrary number of - arguments. - :param count: this flag makes an option increment an integer. - :param allow_from_autoenv: if this is enabled then the value of this - parameter will be pulled from an environment - variable in case a prefix is defined on the - context. - :param help: the help string. - :param hidden: hide this option from help outputs. - :param attrs: Other command arguments described in :class:`Parameter`. - - .. versionchanged:: 8.2 - ``envvar`` used with ``flag_value`` will always use the ``flag_value``, - previously it would use the value of the environment variable. - - .. versionchanged:: 8.1 - Help text indentation is cleaned here instead of only in the - ``@option`` decorator. - - .. versionchanged:: 8.1 - The ``show_default`` parameter overrides - ``Context.show_default``. - - .. versionchanged:: 8.1 - The default of a single option boolean flag is not shown if the - default value is ``False``. - - .. versionchanged:: 8.0.1 - ``type`` is detected from ``flag_value`` if given. - """ - - param_type_name = "option" - - def __init__( - self, - param_decls: cabc.Sequence[str] | None = None, - show_default: bool | str | None = None, - prompt: bool | str = False, - confirmation_prompt: bool | str = False, - prompt_required: bool = True, - hide_input: bool = False, - is_flag: bool | None = None, - flag_value: t.Any = UNSET, - multiple: bool = False, - count: bool = False, - allow_from_autoenv: bool = True, - type: types.ParamType | t.Any | None = None, - help: str | None = None, - hidden: bool = False, - show_choices: bool = True, - show_envvar: bool = False, - deprecated: bool | str = False, - **attrs: t.Any, - ) -> None: - if help: - help = inspect.cleandoc(help) - - super().__init__( - param_decls, type=type, multiple=multiple, deprecated=deprecated, **attrs - ) - - if prompt is True: - if self.name is None: - raise TypeError("'name' is required with 'prompt=True'.") - - prompt_text: str | None = self.name.replace("_", " ").capitalize() - elif prompt is False: - prompt_text = None - else: - prompt_text = prompt - - if deprecated: - deprecated_message = ( - f"(DEPRECATED: {deprecated})" - if isinstance(deprecated, str) - else "(DEPRECATED)" - ) - help = help + deprecated_message if help is not None else deprecated_message - - self.prompt = prompt_text - self.confirmation_prompt = confirmation_prompt - self.prompt_required = prompt_required - self.hide_input = hide_input - self.hidden = hidden - - # The _flag_needs_value property tells the parser that this option is a flag - # that cannot be used standalone and needs a value. With this information, the - # parser can determine whether to consider the next user-provided argument in - # the CLI as a value for this flag or as a new option. - # If prompt is enabled but not required, then it opens the possibility for the - # option to gets its value from the user. - self._flag_needs_value = self.prompt is not None and not self.prompt_required - - # Auto-detect if this is a flag or not. - if is_flag is None: - # Implicitly a flag because flag_value was set. - if flag_value is not UNSET: - is_flag = True - # Not a flag, but when used as a flag it shows a prompt. - elif self._flag_needs_value: - is_flag = False - # Implicitly a flag because secondary options names were given. - elif self.secondary_opts: - is_flag = True - # The option is explicitly not a flag. But we do not know yet if it needs a - # value or not. So we look at the default value to determine it. - elif is_flag is False and not self._flag_needs_value: - self._flag_needs_value = self.default is UNSET - - if is_flag: - # Set missing default for flags if not explicitly required or prompted. - if self.default is UNSET and not self.required and not self.prompt: - if multiple: - self.default = () - - # Auto-detect the type of the flag based on the flag_value. - if type is None: - # A flag without a flag_value is a boolean flag. - if flag_value is UNSET: - self.type: types.ParamType = types.BoolParamType() - # If the flag value is a boolean, use BoolParamType. - elif isinstance(flag_value, bool): - self.type = types.BoolParamType() - # Otherwise, guess the type from the flag value. - else: - self.type = types.convert_type(None, flag_value) - - self.is_flag: bool = bool(is_flag) - self.is_bool_flag: bool = bool( - is_flag and isinstance(self.type, types.BoolParamType) - ) - self.flag_value: t.Any = flag_value - - # Set boolean flag default to False if unset and not required. - if self.is_bool_flag: - if self.default is UNSET and not self.required: - self.default = False - - # Support the special case of aligning the default value with the flag_value - # for flags whose default is explicitly set to True. Note that as long as we - # have this condition, there is no way a flag can have a default set to True, - # and a flag_value set to something else. Refs: - # https://github.com/pallets/click/issues/3024#issuecomment-3146199461 - # https://github.com/pallets/click/pull/3030/commits/06847da - if self.default is True and self.flag_value is not UNSET: - self.default = self.flag_value - - # Set the default flag_value if it is not set. - if self.flag_value is UNSET: - if self.is_flag: - self.flag_value = True - else: - self.flag_value = None - - # Counting. - self.count = count - if count: - if type is None: - self.type = types.IntRange(min=0) - if self.default is UNSET: - self.default = 0 - - self.allow_from_autoenv = allow_from_autoenv - self.help = help - self.show_default = show_default - self.show_choices = show_choices - self.show_envvar = show_envvar - - if __debug__: - if deprecated and prompt: - raise ValueError("`deprecated` options cannot use `prompt`.") - - if self.nargs == -1: - raise TypeError("nargs=-1 is not supported for options.") - - if not self.is_bool_flag and self.secondary_opts: - raise TypeError("Secondary flag is not valid for non-boolean flag.") - - if self.is_bool_flag and self.hide_input and self.prompt is not None: - raise TypeError( - "'prompt' with 'hide_input' is not valid for boolean flag." - ) - - if self.count: - if self.multiple: - raise TypeError("'count' is not valid with 'multiple'.") - - if self.is_flag: - raise TypeError("'count' is not valid with 'is_flag'.") - - def to_info_dict(self) -> dict[str, t.Any]: - """ - .. versionchanged:: 8.3.0 - Returns ``None`` for the :attr:`flag_value` if it was not set. - """ - info_dict = super().to_info_dict() - info_dict.update( - help=self.help, - prompt=self.prompt, - is_flag=self.is_flag, - # We explicitly hide the :attr:`UNSET` value to the user, as we choose to - # make it an implementation detail. And because ``to_info_dict`` has been - # designed for documentation purposes, we return ``None`` instead. - flag_value=self.flag_value if self.flag_value is not UNSET else None, - count=self.count, - hidden=self.hidden, - ) - return info_dict - - def get_error_hint(self, ctx: Context) -> str: - result = super().get_error_hint(ctx) - if self.show_envvar and self.envvar is not None: - result += f" (env var: '{self.envvar}')" - return result - - def _parse_decls( - self, decls: cabc.Sequence[str], expose_value: bool - ) -> tuple[str | None, list[str], list[str]]: - opts = [] - secondary_opts = [] - name = None - possible_names = [] - - for decl in decls: - if decl.isidentifier(): - if name is not None: - raise TypeError(f"Name '{name}' defined twice") - name = decl - else: - split_char = ";" if decl[:1] == "/" else "/" - if split_char in decl: - first, second = decl.split(split_char, 1) - first = first.rstrip() - if first: - possible_names.append(_split_opt(first)) - opts.append(first) - second = second.lstrip() - if second: - secondary_opts.append(second.lstrip()) - if first == second: - raise ValueError( - f"Boolean option {decl!r} cannot use the" - " same flag for true/false." - ) - else: - possible_names.append(_split_opt(decl)) - opts.append(decl) - - if name is None and possible_names: - possible_names.sort(key=lambda x: -len(x[0])) # group long options first - name = possible_names[0][1].replace("-", "_").lower() - if not name.isidentifier(): - name = None - - if name is None: - if not expose_value: - return None, opts, secondary_opts - raise TypeError( - f"Could not determine name for option with declarations {decls!r}" - ) - - if not opts and not secondary_opts: - raise TypeError( - f"No options defined but a name was passed ({name})." - " Did you mean to declare an argument instead? Did" - f" you mean to pass '--{name}'?" - ) - - return name, opts, secondary_opts - - def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: - if self.multiple: - action = "append" - elif self.count: - action = "count" - else: - action = "store" - - if self.is_flag: - action = f"{action}_const" - - if self.is_bool_flag and self.secondary_opts: - parser.add_option( - obj=self, opts=self.opts, dest=self.name, action=action, const=True - ) - parser.add_option( - obj=self, - opts=self.secondary_opts, - dest=self.name, - action=action, - const=False, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - const=self.flag_value, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - nargs=self.nargs, - ) - - def get_help_record(self, ctx: Context) -> tuple[str, str] | None: - if self.hidden: - return None - - any_prefix_is_slash = False - - def _write_opts(opts: cabc.Sequence[str]) -> str: - nonlocal any_prefix_is_slash - - rv, any_slashes = join_options(opts) - - if any_slashes: - any_prefix_is_slash = True - - if not self.is_flag and not self.count: - rv += f" {self.make_metavar(ctx=ctx)}" - - return rv - - rv = [_write_opts(self.opts)] - - if self.secondary_opts: - rv.append(_write_opts(self.secondary_opts)) - - help = self.help or "" - - extra = self.get_help_extra(ctx) - extra_items = [] - if "envvars" in extra: - extra_items.append( - _("env var: {var}").format(var=", ".join(extra["envvars"])) - ) - if "default" in extra: - extra_items.append(_("default: {default}").format(default=extra["default"])) - if "range" in extra: - extra_items.append(extra["range"]) - if "required" in extra: - extra_items.append(_(extra["required"])) - - if extra_items: - extra_str = "; ".join(extra_items) - help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" - - return ("; " if any_prefix_is_slash else " / ").join(rv), help - - def get_help_extra(self, ctx: Context) -> types.OptionHelpExtra: - extra: types.OptionHelpExtra = {} - - if self.show_envvar: - envvar = self.envvar - - if envvar is None: - if ( - self.allow_from_autoenv - and ctx.auto_envvar_prefix is not None - and self.name is not None - ): - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - - if envvar is not None: - if isinstance(envvar, str): - extra["envvars"] = (envvar,) - else: - extra["envvars"] = tuple(str(d) for d in envvar) - - # Temporarily enable resilient parsing to avoid type casting - # failing for the default. Might be possible to extend this to - # help formatting in general. - resilient = ctx.resilient_parsing - ctx.resilient_parsing = True - - try: - default_value = self.get_default(ctx, call=False) - finally: - ctx.resilient_parsing = resilient - - show_default = False - show_default_is_str = False - - if self.show_default is not None: - if isinstance(self.show_default, str): - show_default_is_str = show_default = True - else: - show_default = self.show_default - elif ctx.show_default is not None: - show_default = ctx.show_default - - if show_default_is_str or ( - show_default and (default_value not in (None, UNSET)) - ): - if show_default_is_str: - default_string = f"({self.show_default})" - elif isinstance(default_value, (list, tuple)): - default_string = ", ".join(str(d) for d in default_value) - elif isinstance(default_value, enum.Enum): - default_string = default_value.name - elif inspect.isfunction(default_value): - default_string = _("(dynamic)") - elif self.is_bool_flag and self.secondary_opts: - # For boolean flags that have distinct True/False opts, - # use the opt without prefix instead of the value. - default_string = _split_opt( - (self.opts if default_value else self.secondary_opts)[0] - )[1] - elif self.is_bool_flag and not self.secondary_opts and not default_value: - default_string = "" - elif default_value == "": - default_string = '""' - else: - default_string = str(default_value) - - if default_string: - extra["default"] = default_string - - if ( - isinstance(self.type, types._NumberRangeBase) - # skip count with default range type - and not (self.count and self.type.min == 0 and self.type.max is None) - ): - range_str = self.type._describe_range() - - if range_str: - extra["range"] = range_str - - if self.required: - extra["required"] = "required" - - return extra - - def prompt_for_value(self, ctx: Context) -> t.Any: - """This is an alternative flow that can be activated in the full - value processing if a value does not exist. It will prompt the - user until a valid value exists and then returns the processed - value as result. - """ - assert self.prompt is not None - - # Calculate the default before prompting anything to lock in the value before - # attempting any user interaction. - default = self.get_default(ctx) - - # A boolean flag can use a simplified [y/n] confirmation prompt. - if self.is_bool_flag: - # If we have no boolean default, we force the user to explicitly provide - # one. - if default in (UNSET, None): - default = None - # Nothing prevent you to declare an option that is simultaneously: - # 1) auto-detected as a boolean flag, - # 2) allowed to prompt, and - # 3) still declare a non-boolean default. - # This forced casting into a boolean is necessary to align any non-boolean - # default to the prompt, which is going to be a [y/n]-style confirmation - # because the option is still a boolean flag. That way, instead of [y/n], - # we get [Y/n] or [y/N] depending on the truthy value of the default. - # Refs: https://github.com/pallets/click/pull/3030#discussion_r2289180249 - else: - default = bool(default) - return confirm(self.prompt, default) - - # If show_default is set to True/False, provide this to `prompt` as well. For - # non-bool values of `show_default`, we use `prompt`'s default behavior - prompt_kwargs: t.Any = {} - if isinstance(self.show_default, bool): - prompt_kwargs["show_default"] = self.show_default - - return prompt( - self.prompt, - # Use ``None`` to inform the prompt() function to reiterate until a valid - # value is provided by the user if we have no default. - default=None if default is UNSET else default, - type=self.type, - hide_input=self.hide_input, - show_choices=self.show_choices, - confirmation_prompt=self.confirmation_prompt, - value_proc=lambda x: self.process_value(ctx, x), - **prompt_kwargs, - ) - - def resolve_envvar_value(self, ctx: Context) -> str | None: - """:class:`Option` resolves its environment variable the same way as - :func:`Parameter.resolve_envvar_value`, but it also supports - :attr:`Context.auto_envvar_prefix`. If we could not find an environment from - the :attr:`envvar` property, we fallback on :attr:`Context.auto_envvar_prefix` - to build dynamiccaly the environment variable name using the - :python:`{ctx.auto_envvar_prefix}_{self.name.upper()}` template. - - :meta private: - """ - rv = super().resolve_envvar_value(ctx) - - if rv is not None: - return rv - - if ( - self.allow_from_autoenv - and ctx.auto_envvar_prefix is not None - and self.name is not None - ): - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - rv = os.environ.get(envvar) - - if rv: - return rv - - return None - - def value_from_envvar(self, ctx: Context) -> t.Any: - """For :class:`Option`, this method processes the raw environment variable - string the same way as :func:`Parameter.value_from_envvar` does. - - But in the case of non-boolean flags, the value is analyzed to determine if the - flag is activated or not, and returns a boolean of its activation, or the - :attr:`flag_value` if the latter is set. - - This method also takes care of repeated options (i.e. options with - :attr:`multiple` set to ``True``). - - :meta private: - """ - rv = self.resolve_envvar_value(ctx) - - # Absent environment variable or an empty string is interpreted as unset. - if rv is None: - return None - - # Non-boolean flags are more liberal in what they accept. But a flag being a - # flag, its envvar value still needs to be analyzed to determine if the flag is - # activated or not. - if self.is_flag and not self.is_bool_flag: - # If the flag_value is set and match the envvar value, return it - # directly. - if self.flag_value is not UNSET and rv == self.flag_value: - return self.flag_value - # Analyze the envvar value as a boolean to know if the flag is - # activated or not. - return types.BoolParamType.str_to_bool(rv) - - # Split the envvar value if it is allowed to be repeated. - value_depth = (self.nargs != 1) + bool(self.multiple) - if value_depth > 0: - multi_rv = self.type.split_envvar_value(rv) - if self.multiple and self.nargs != 1: - multi_rv = batch(multi_rv, self.nargs) # type: ignore[assignment] - - return multi_rv - - return rv - - def consume_value( - self, ctx: Context, opts: cabc.Mapping[str, Parameter] - ) -> tuple[t.Any, ParameterSource]: - """For :class:`Option`, the value can be collected from an interactive prompt - if the option is a flag that needs a value (and the :attr:`prompt` property is - set). - - Additionally, this method handles flag option that are activated without a - value, in which case the :attr:`flag_value` is returned. - - :meta private: - """ - value, source = super().consume_value(ctx, opts) - - # The parser will emit a sentinel value if the option is allowed to as a flag - # without a value. - if value is FLAG_NEEDS_VALUE: - # If the option allows for a prompt, we start an interaction with the user. - if self.prompt is not None and not ctx.resilient_parsing: - value = self.prompt_for_value(ctx) - source = ParameterSource.PROMPT - # Else the flag takes its flag_value as value. - else: - value = self.flag_value - source = ParameterSource.COMMANDLINE - - # A flag which is activated always returns the flag value, unless the value - # comes from the explicitly sets default. - elif ( - self.is_flag - and value is True - and not self.is_bool_flag - and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) - ): - value = self.flag_value - - # Re-interpret a multiple option which has been sent as-is by the parser. - # Here we replace each occurrence of value-less flags (marked by the - # FLAG_NEEDS_VALUE sentinel) with the flag_value. - elif ( - self.multiple - and value is not UNSET - and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) - and any(v is FLAG_NEEDS_VALUE for v in value) - ): - value = [self.flag_value if v is FLAG_NEEDS_VALUE else v for v in value] - source = ParameterSource.COMMANDLINE - - # The value wasn't set, or used the param's default, prompt for one to the user - # if prompting is enabled. - elif ( - ( - value is UNSET - or source in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) - ) - and self.prompt is not None - and (self.required or self.prompt_required) - and not ctx.resilient_parsing - ): - value = self.prompt_for_value(ctx) - source = ParameterSource.PROMPT - - return value, source - - def process_value(self, ctx: Context, value: t.Any) -> t.Any: - # process_value has to be overridden on Options in order to capture - # `value == UNSET` cases before `type_cast_value()` gets called. - # - # Refs: - # https://github.com/pallets/click/issues/3069 - if self.is_flag and not self.required and self.is_bool_flag and value is UNSET: - value = False - - if self.callback is not None: - value = self.callback(ctx, self, value) - - return value - - # in the normal case, rely on Parameter.process_value - return super().process_value(ctx, value) - - -class Argument(Parameter): - """Arguments are positional parameters to a command. They generally - provide fewer features than options but can have infinite ``nargs`` - and are required by default. - - All parameters are passed onwards to the constructor of :class:`Parameter`. - """ - - param_type_name = "argument" - - def __init__( - self, - param_decls: cabc.Sequence[str], - required: bool | None = None, - **attrs: t.Any, - ) -> None: - # Auto-detect the requirement status of the argument if not explicitly set. - if required is None: - # The argument gets automatically required if it has no explicit default - # value set and is setup to match at least one value. - if attrs.get("default", UNSET) is UNSET: - required = attrs.get("nargs", 1) > 0 - # If the argument has a default value, it is not required. - else: - required = False - - if "multiple" in attrs: - raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") - - super().__init__(param_decls, required=required, **attrs) - - @property - def human_readable_name(self) -> str: - if self.metavar is not None: - return self.metavar - return self.name.upper() # type: ignore - - def make_metavar(self, ctx: Context) -> str: - if self.metavar is not None: - return self.metavar - var = self.type.get_metavar(param=self, ctx=ctx) - if not var: - var = self.name.upper() # type: ignore - if self.deprecated: - var += "!" - if not self.required: - var = f"[{var}]" - if self.nargs != 1: - var += "..." - return var - - def _parse_decls( - self, decls: cabc.Sequence[str], expose_value: bool - ) -> tuple[str | None, list[str], list[str]]: - if not decls: - if not expose_value: - return None, [], [] - raise TypeError("Argument is marked as exposed, but does not have a name.") - if len(decls) == 1: - name = arg = decls[0] - name = name.replace("-", "_").lower() - else: - raise TypeError( - "Arguments take exactly one parameter declaration, got" - f" {len(decls)}: {decls}." - ) - return name, [arg], [] - - def get_usage_pieces(self, ctx: Context) -> list[str]: - return [self.make_metavar(ctx)] - - def get_error_hint(self, ctx: Context) -> str: - return f"'{self.make_metavar(ctx)}'" - - def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: - parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) - - -def __getattr__(name: str) -> object: - import warnings - - if name == "BaseCommand": - warnings.warn( - "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Command' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _BaseCommand - - if name == "MultiCommand": - warnings.warn( - "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" - " 'Group' instead.", - DeprecationWarning, - stacklevel=2, - ) - return _MultiCommand - - raise AttributeError(name) diff --git a/venv/lib/python3.10/site-packages/click/decorators.py b/venv/lib/python3.10/site-packages/click/decorators.py deleted file mode 100644 index 21f4c342245fa93a7946b17d7661e0d2fa6a0c29..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/decorators.py +++ /dev/null @@ -1,551 +0,0 @@ -from __future__ import annotations - -import inspect -import typing as t -from functools import update_wrapper -from gettext import gettext as _ - -from .core import Argument -from .core import Command -from .core import Context -from .core import Group -from .core import Option -from .core import Parameter -from .globals import get_current_context -from .utils import echo - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") -T = t.TypeVar("T") -_AnyCallable = t.Callable[..., t.Any] -FC = t.TypeVar("FC", bound="_AnyCallable | Command") - - -def pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]: - """Marks a callback as wanting to receive the current context - object as first argument. - """ - - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - return f(get_current_context(), *args, **kwargs) - - return update_wrapper(new_func, f) - - -def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: - """Similar to :func:`pass_context`, but only pass the object on the - context onwards (:attr:`Context.obj`). This is useful if that object - represents the state of a nested system. - """ - - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - return f(get_current_context().obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - -def make_pass_decorator( - object_type: type[T], ensure: bool = False -) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: - """Given an object type this creates a decorator that will work - similar to :func:`pass_obj` but instead of passing the object of the - current context, it will find the innermost context of type - :func:`object_type`. - - This generates a decorator that works roughly like this:: - - from functools import update_wrapper - - def decorator(f): - @pass_context - def new_func(ctx, *args, **kwargs): - obj = ctx.find_object(object_type) - return ctx.invoke(f, obj, *args, **kwargs) - return update_wrapper(new_func, f) - return decorator - - :param object_type: the type of the object to pass. - :param ensure: if set to `True`, a new object will be created and - remembered on the context if it's not there yet. - """ - - def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - ctx = get_current_context() - - obj: T | None - if ensure: - obj = ctx.ensure_object(object_type) - else: - obj = ctx.find_object(object_type) - - if obj is None: - raise RuntimeError( - "Managed to invoke callback without a context" - f" object of type {object_type.__name__!r}" - " existing." - ) - - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - return decorator - - -def pass_meta_key( - key: str, *, doc_description: str | None = None -) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: - """Create a decorator that passes a key from - :attr:`click.Context.meta` as the first argument to the decorated - function. - - :param key: Key in ``Context.meta`` to pass. - :param doc_description: Description of the object being passed, - inserted into the decorator's docstring. Defaults to "the 'key' - key from Context.meta". - - .. versionadded:: 8.0 - """ - - def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - ctx = get_current_context() - obj = ctx.meta[key] - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - if doc_description is None: - doc_description = f"the {key!r} key from :attr:`click.Context.meta`" - - decorator.__doc__ = ( - f"Decorator that passes {doc_description} as the first argument" - " to the decorated function." - ) - return decorator - - -CmdType = t.TypeVar("CmdType", bound=Command) - - -# variant: no call, directly as decorator for a function. -@t.overload -def command(name: _AnyCallable) -> Command: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) -@t.overload -def command( - name: str | None, - cls: type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) -@t.overload -def command( - name: None = None, - *, - cls: type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def command( - name: str | None = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Command]: ... - - -def command( - name: str | _AnyCallable | None = None, - cls: type[CmdType] | None = None, - **attrs: t.Any, -) -> Command | t.Callable[[_AnyCallable], Command | CmdType]: - r"""Creates a new :class:`Command` and uses the decorated function as - callback. This will also automatically attach all decorated - :func:`option`\s and :func:`argument`\s as parameters to the command. - - The name of the command defaults to the name of the function, converted to - lowercase, with underscores ``_`` replaced by dashes ``-``, and the suffixes - ``_command``, ``_cmd``, ``_group``, and ``_grp`` are removed. For example, - ``init_data_command`` becomes ``init-data``. - - All keyword arguments are forwarded to the underlying command class. - For the ``params`` argument, any decorated params are appended to - the end of the list. - - Once decorated the function turns into a :class:`Command` instance - that can be invoked as a command line utility or be attached to a - command :class:`Group`. - - :param name: The name of the command. Defaults to modifying the function's - name as described above. - :param cls: The command class to create. Defaults to :class:`Command`. - - .. versionchanged:: 8.2 - The suffixes ``_command``, ``_cmd``, ``_group``, and ``_grp`` are - removed when generating the name. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.1 - The ``params`` argument can be used. Decorated params are - appended to the end of the list. - """ - - func: t.Callable[[_AnyCallable], t.Any] | None = None - - if callable(name): - func = name - name = None - assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." - assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." - - if cls is None: - cls = t.cast("type[CmdType]", Command) - - def decorator(f: _AnyCallable) -> CmdType: - if isinstance(f, Command): - raise TypeError("Attempted to convert a callback into a command twice.") - - attr_params = attrs.pop("params", None) - params = attr_params if attr_params is not None else [] - - try: - decorator_params = f.__click_params__ # type: ignore - except AttributeError: - pass - else: - del f.__click_params__ # type: ignore - params.extend(reversed(decorator_params)) - - if attrs.get("help") is None: - attrs["help"] = f.__doc__ - - if t.TYPE_CHECKING: - assert cls is not None - assert not callable(name) - - if name is not None: - cmd_name = name - else: - cmd_name = f.__name__.lower().replace("_", "-") - cmd_left, sep, suffix = cmd_name.rpartition("-") - - if sep and suffix in {"command", "cmd", "group", "grp"}: - cmd_name = cmd_left - - cmd = cls(name=cmd_name, callback=f, params=params, **attrs) - cmd.__doc__ = f.__doc__ - return cmd - - if func is not None: - return decorator(func) - - return decorator - - -GrpType = t.TypeVar("GrpType", bound=Group) - - -# variant: no call, directly as decorator for a function. -@t.overload -def group(name: _AnyCallable) -> Group: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) -@t.overload -def group( - name: str | None, - cls: type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) -@t.overload -def group( - name: None = None, - *, - cls: type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def group( - name: str | None = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Group]: ... - - -def group( - name: str | _AnyCallable | None = None, - cls: type[GrpType] | None = None, - **attrs: t.Any, -) -> Group | t.Callable[[_AnyCallable], Group | GrpType]: - """Creates a new :class:`Group` with a function as callback. This - works otherwise the same as :func:`command` just that the `cls` - parameter is set to :class:`Group`. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - """ - if cls is None: - cls = t.cast("type[GrpType]", Group) - - if callable(name): - return command(cls=cls, **attrs)(name) - - return command(name, cls, **attrs) - - -def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: - if isinstance(f, Command): - f.params.append(param) - else: - if not hasattr(f, "__click_params__"): - f.__click_params__ = [] # type: ignore - - f.__click_params__.append(param) # type: ignore - - -def argument( - *param_decls: str, cls: type[Argument] | None = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an argument to the command. All positional arguments are - passed as parameter declarations to :class:`Argument`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Argument` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default argument class, refer to :class:`Argument` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the argument class to instantiate. This defaults to - :class:`Argument`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Argument - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def option( - *param_decls: str, cls: type[Option] | None = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an option to the command. All positional arguments are - passed as parameter declarations to :class:`Option`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Option` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default option class, refer to :class:`Option` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the option class to instantiate. This defaults to - :class:`Option`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Option - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--yes`` option which shows a prompt before continuing if - not passed. If the prompt is declined, the program will exit. - - :param param_decls: One or more option names. Defaults to the single - value ``"--yes"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value: - ctx.abort() - - if not param_decls: - param_decls = ("--yes",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("callback", callback) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("prompt", "Do you want to continue?") - kwargs.setdefault("help", "Confirm the action without prompting.") - return option(*param_decls, **kwargs) - - -def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--password`` option which prompts for a password, hiding - input and asking to enter the value again for confirmation. - - :param param_decls: One or more option names. Defaults to the single - value ``"--password"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - if not param_decls: - param_decls = ("--password",) - - kwargs.setdefault("prompt", True) - kwargs.setdefault("confirmation_prompt", True) - kwargs.setdefault("hide_input", True) - return option(*param_decls, **kwargs) - - -def version_option( - version: str | None = None, - *param_decls: str, - package_name: str | None = None, - prog_name: str | None = None, - message: str | None = None, - **kwargs: t.Any, -) -> t.Callable[[FC], FC]: - """Add a ``--version`` option which immediately prints the version - number and exits the program. - - If ``version`` is not provided, Click will try to detect it using - :func:`importlib.metadata.version` to get the version for the - ``package_name``. - - If ``package_name`` is not provided, Click will try to detect it by - inspecting the stack frames. This will be used to detect the - version, so it must match the name of the installed package. - - :param version: The version number to show. If not provided, Click - will try to detect it. - :param param_decls: One or more option names. Defaults to the single - value ``"--version"``. - :param package_name: The package name to detect the version from. If - not provided, Click will try to detect it. - :param prog_name: The name of the CLI to show in the message. If not - provided, it will be detected from the command. - :param message: The message to show. The values ``%(prog)s``, - ``%(package)s``, and ``%(version)s`` are available. Defaults to - ``"%(prog)s, version %(version)s"``. - :param kwargs: Extra arguments are passed to :func:`option`. - :raise RuntimeError: ``version`` could not be detected. - - .. versionchanged:: 8.0 - Add the ``package_name`` parameter, and the ``%(package)s`` - value for messages. - - .. versionchanged:: 8.0 - Use :mod:`importlib.metadata` instead of ``pkg_resources``. The - version is detected based on the package name, not the entry - point name. The Python package name must match the installed - package name, or be passed with ``package_name=``. - """ - if message is None: - message = _("%(prog)s, version %(version)s") - - if version is None and package_name is None: - frame = inspect.currentframe() - f_back = frame.f_back if frame is not None else None - f_globals = f_back.f_globals if f_back is not None else None - # break reference cycle - # https://docs.python.org/3/library/inspect.html#the-interpreter-stack - del frame - - if f_globals is not None: - package_name = f_globals.get("__name__") - - if package_name == "__main__": - package_name = f_globals.get("__package__") - - if package_name: - package_name = package_name.partition(".")[0] - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value or ctx.resilient_parsing: - return - - nonlocal prog_name - nonlocal version - - if prog_name is None: - prog_name = ctx.find_root().info_name - - if version is None and package_name is not None: - import importlib.metadata - - try: - version = importlib.metadata.version(package_name) - except importlib.metadata.PackageNotFoundError: - raise RuntimeError( - f"{package_name!r} is not installed. Try passing" - " 'package_name' instead." - ) from None - - if version is None: - raise RuntimeError( - f"Could not determine the version for {package_name!r} automatically." - ) - - echo( - message % {"prog": prog_name, "package": package_name, "version": version}, - color=ctx.color, - ) - ctx.exit() - - if not param_decls: - param_decls = ("--version",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show the version and exit.")) - kwargs["callback"] = callback - return option(*param_decls, **kwargs) - - -def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Pre-configured ``--help`` option which immediately prints the help page - and exits the program. - - :param param_decls: One or more option names. Defaults to the single - value ``"--help"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - - def show_help(ctx: Context, param: Parameter, value: bool) -> None: - """Callback that print the help page on ```` and exits.""" - if value and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - if not param_decls: - param_decls = ("--help",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show this message and exit.")) - kwargs.setdefault("callback", show_help) - - return option(*param_decls, **kwargs) diff --git a/venv/lib/python3.10/site-packages/click/exceptions.py b/venv/lib/python3.10/site-packages/click/exceptions.py deleted file mode 100644 index 4d782ee361442e4aafeac7e371ab12789c8a3751..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/exceptions.py +++ /dev/null @@ -1,308 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import typing as t -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import get_text_stderr -from .globals import resolve_color_default -from .utils import echo -from .utils import format_filename - -if t.TYPE_CHECKING: - from .core import Command - from .core import Context - from .core import Parameter - - -def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: - if param_hint is not None and not isinstance(param_hint, str): - return " / ".join(repr(x) for x in param_hint) - - return param_hint - - -class ClickException(Exception): - """An exception that Click can handle and show to the user.""" - - #: The exit code for this exception. - exit_code = 1 - - def __init__(self, message: str) -> None: - super().__init__(message) - # The context will be removed by the time we print the message, so cache - # the color settings here to be used later on (in `show`) - self.show_color: bool | None = resolve_color_default() - self.message = message - - def format_message(self) -> str: - return self.message - - def __str__(self) -> str: - return self.message - - def show(self, file: t.IO[t.Any] | None = None) -> None: - if file is None: - file = get_text_stderr() - - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=self.show_color, - ) - - -class UsageError(ClickException): - """An internal exception that signals a usage error. This typically - aborts any further handling. - - :param message: the error message to display. - :param ctx: optionally the context that caused this error. Click will - fill in the context automatically in some situations. - """ - - exit_code = 2 - - def __init__(self, message: str, ctx: Context | None = None) -> None: - super().__init__(message) - self.ctx = ctx - self.cmd: Command | None = self.ctx.command if self.ctx else None - - def show(self, file: t.IO[t.Any] | None = None) -> None: - if file is None: - file = get_text_stderr() - color = None - hint = "" - if ( - self.ctx is not None - and self.ctx.command.get_help_option(self.ctx) is not None - ): - hint = _("Try '{command} {option}' for help.").format( - command=self.ctx.command_path, option=self.ctx.help_option_names[0] - ) - hint = f"{hint}\n" - if self.ctx is not None: - color = self.ctx.color - echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=color, - ) - - -class BadParameter(UsageError): - """An exception that formats out a standardized error message for a - bad parameter. This is useful when thrown from a callback or type as - Click will attach contextual information to it (for instance, which - parameter it is). - - .. versionadded:: 2.0 - - :param param: the parameter object that caused this error. This can - be left out, and Click will attach this info itself - if possible. - :param param_hint: a string that shows up as parameter name. This - can be used as alternative to `param` in cases - where custom validation should happen. If it is - a string it's used as such, if it's a list then - each item is quoted and separated. - """ - - def __init__( - self, - message: str, - ctx: Context | None = None, - param: Parameter | None = None, - param_hint: cabc.Sequence[str] | str | None = None, - ) -> None: - super().__init__(message, ctx) - self.param = param - self.param_hint = param_hint - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) # type: ignore - else: - return _("Invalid value: {message}").format(message=self.message) - - return _("Invalid value for {param_hint}: {message}").format( - param_hint=_join_param_hints(param_hint), message=self.message - ) - - -class MissingParameter(BadParameter): - """Raised if click required an option or argument but it was not - provided when invoking the script. - - .. versionadded:: 4.0 - - :param param_type: a string that indicates the type of the parameter. - The default is to inherit the parameter type from - the given `param`. Valid values are ``'parameter'``, - ``'option'`` or ``'argument'``. - """ - - def __init__( - self, - message: str | None = None, - ctx: Context | None = None, - param: Parameter | None = None, - param_hint: cabc.Sequence[str] | str | None = None, - param_type: str | None = None, - ) -> None: - super().__init__(message or "", ctx, param, param_hint) - self.param_type = param_type - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint: cabc.Sequence[str] | str | None = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) # type: ignore - else: - param_hint = None - - param_hint = _join_param_hints(param_hint) - param_hint = f" {param_hint}" if param_hint else "" - - param_type = self.param_type - if param_type is None and self.param is not None: - param_type = self.param.param_type_name - - msg = self.message - if self.param is not None: - msg_extra = self.param.type.get_missing_message( - param=self.param, ctx=self.ctx - ) - if msg_extra: - if msg: - msg += f". {msg_extra}" - else: - msg = msg_extra - - msg = f" {msg}" if msg else "" - - # Translate param_type for known types. - if param_type == "argument": - missing = _("Missing argument") - elif param_type == "option": - missing = _("Missing option") - elif param_type == "parameter": - missing = _("Missing parameter") - else: - missing = _("Missing {param_type}").format(param_type=param_type) - - return f"{missing}{param_hint}.{msg}" - - def __str__(self) -> str: - if not self.message: - param_name = self.param.name if self.param else None - return _("Missing parameter: {param_name}").format(param_name=param_name) - else: - return self.message - - -class NoSuchOption(UsageError): - """Raised if click attempted to handle an option that does not - exist. - - .. versionadded:: 4.0 - """ - - def __init__( - self, - option_name: str, - message: str | None = None, - possibilities: cabc.Sequence[str] | None = None, - ctx: Context | None = None, - ) -> None: - if message is None: - message = _("No such option: {name}").format(name=option_name) - - super().__init__(message, ctx) - self.option_name = option_name - self.possibilities = possibilities - - def format_message(self) -> str: - if not self.possibilities: - return self.message - - possibility_str = ", ".join(sorted(self.possibilities)) - suggest = ngettext( - "Did you mean {possibility}?", - "(Possible options: {possibilities})", - len(self.possibilities), - ).format(possibility=possibility_str, possibilities=possibility_str) - return f"{self.message} {suggest}" - - -class BadOptionUsage(UsageError): - """Raised if an option is generally supplied but the use of the option - was incorrect. This is for instance raised if the number of arguments - for an option is not correct. - - .. versionadded:: 4.0 - - :param option_name: the name of the option being used incorrectly. - """ - - def __init__( - self, option_name: str, message: str, ctx: Context | None = None - ) -> None: - super().__init__(message, ctx) - self.option_name = option_name - - -class BadArgumentUsage(UsageError): - """Raised if an argument is generally supplied but the use of the argument - was incorrect. This is for instance raised if the number of values - for an argument is not correct. - - .. versionadded:: 6.0 - """ - - -class NoArgsIsHelpError(UsageError): - def __init__(self, ctx: Context) -> None: - self.ctx: Context - super().__init__(ctx.get_help(), ctx=ctx) - - def show(self, file: t.IO[t.Any] | None = None) -> None: - echo(self.format_message(), file=file, err=True, color=self.ctx.color) - - -class FileError(ClickException): - """Raised if a file cannot be opened.""" - - def __init__(self, filename: str, hint: str | None = None) -> None: - if hint is None: - hint = _("unknown error") - - super().__init__(hint) - self.ui_filename: str = format_filename(filename) - self.filename = filename - - def format_message(self) -> str: - return _("Could not open file {filename!r}: {message}").format( - filename=self.ui_filename, message=self.message - ) - - -class Abort(RuntimeError): - """An internal signalling exception that signals Click to abort.""" - - -class Exit(RuntimeError): - """An exception that indicates that the application should exit with some - status code. - - :param code: the status code to exit with. - """ - - __slots__ = ("exit_code",) - - def __init__(self, code: int = 0) -> None: - self.exit_code: int = code diff --git a/venv/lib/python3.10/site-packages/click/formatting.py b/venv/lib/python3.10/site-packages/click/formatting.py deleted file mode 100644 index 0b64f831b5578e7262302ec9218fa498a2336794..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/formatting.py +++ /dev/null @@ -1,301 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -from contextlib import contextmanager -from gettext import gettext as _ - -from ._compat import term_len -from .parser import _split_opt - -# Can force a width. This is used by the test system -FORCED_WIDTH: int | None = None - - -def measure_table(rows: cabc.Iterable[tuple[str, str]]) -> tuple[int, ...]: - widths: dict[int, int] = {} - - for row in rows: - for idx, col in enumerate(row): - widths[idx] = max(widths.get(idx, 0), term_len(col)) - - return tuple(y for x, y in sorted(widths.items())) - - -def iter_rows( - rows: cabc.Iterable[tuple[str, str]], col_count: int -) -> cabc.Iterator[tuple[str, ...]]: - for row in rows: - yield row + ("",) * (col_count - len(row)) - - -def wrap_text( - text: str, - width: int = 78, - initial_indent: str = "", - subsequent_indent: str = "", - preserve_paragraphs: bool = False, -) -> str: - """A helper function that intelligently wraps text. By default, it - assumes that it operates on a single paragraph of text but if the - `preserve_paragraphs` parameter is provided it will intelligently - handle paragraphs (defined by two empty lines). - - If paragraphs are handled, a paragraph can be prefixed with an empty - line containing the ``\\b`` character (``\\x08``) to indicate that - no rewrapping should happen in that block. - - :param text: the text that should be rewrapped. - :param width: the maximum width for the text. - :param initial_indent: the initial indent that should be placed on the - first line as a string. - :param subsequent_indent: the indent string that should be placed on - each consecutive line. - :param preserve_paragraphs: if this flag is set then the wrapping will - intelligently handle paragraphs. - """ - from ._textwrap import TextWrapper - - text = text.expandtabs() - wrapper = TextWrapper( - width, - initial_indent=initial_indent, - subsequent_indent=subsequent_indent, - replace_whitespace=False, - ) - if not preserve_paragraphs: - return wrapper.fill(text) - - p: list[tuple[int, bool, str]] = [] - buf: list[str] = [] - indent = None - - def _flush_par() -> None: - if not buf: - return - if buf[0].strip() == "\b": - p.append((indent or 0, True, "\n".join(buf[1:]))) - else: - p.append((indent or 0, False, " ".join(buf))) - del buf[:] - - for line in text.splitlines(): - if not line: - _flush_par() - indent = None - else: - if indent is None: - orig_len = term_len(line) - line = line.lstrip() - indent = orig_len - term_len(line) - buf.append(line) - _flush_par() - - rv = [] - for indent, raw, text in p: - with wrapper.extra_indent(" " * indent): - if raw: - rv.append(wrapper.indent_only(text)) - else: - rv.append(wrapper.fill(text)) - - return "\n\n".join(rv) - - -class HelpFormatter: - """This class helps with formatting text-based help pages. It's - usually just needed for very special internal cases, but it's also - exposed so that developers can write their own fancy outputs. - - At present, it always writes into memory. - - :param indent_increment: the additional increment for each level. - :param width: the width for the text. This defaults to the terminal - width clamped to a maximum of 78. - """ - - def __init__( - self, - indent_increment: int = 2, - width: int | None = None, - max_width: int | None = None, - ) -> None: - self.indent_increment = indent_increment - if max_width is None: - max_width = 80 - if width is None: - import shutil - - width = FORCED_WIDTH - if width is None: - width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) - self.width = width - self.current_indent: int = 0 - self.buffer: list[str] = [] - - def write(self, string: str) -> None: - """Writes a unicode string into the internal buffer.""" - self.buffer.append(string) - - def indent(self) -> None: - """Increases the indentation.""" - self.current_indent += self.indent_increment - - def dedent(self) -> None: - """Decreases the indentation.""" - self.current_indent -= self.indent_increment - - def write_usage(self, prog: str, args: str = "", prefix: str | None = None) -> None: - """Writes a usage line into the buffer. - - :param prog: the program name. - :param args: whitespace separated list of arguments. - :param prefix: The prefix for the first line. Defaults to - ``"Usage: "``. - """ - if prefix is None: - prefix = f"{_('Usage:')} " - - usage_prefix = f"{prefix:>{self.current_indent}}{prog} " - text_width = self.width - self.current_indent - - if text_width >= (term_len(usage_prefix) + 20): - # The arguments will fit to the right of the prefix. - indent = " " * term_len(usage_prefix) - self.write( - wrap_text( - args, - text_width, - initial_indent=usage_prefix, - subsequent_indent=indent, - ) - ) - else: - # The prefix is too long, put the arguments on the next line. - self.write(usage_prefix) - self.write("\n") - indent = " " * (max(self.current_indent, term_len(prefix)) + 4) - self.write( - wrap_text( - args, text_width, initial_indent=indent, subsequent_indent=indent - ) - ) - - self.write("\n") - - def write_heading(self, heading: str) -> None: - """Writes a heading into the buffer.""" - self.write(f"{'':>{self.current_indent}}{heading}:\n") - - def write_paragraph(self) -> None: - """Writes a paragraph into the buffer.""" - if self.buffer: - self.write("\n") - - def write_text(self, text: str) -> None: - """Writes re-indented text into the buffer. This rewraps and - preserves paragraphs. - """ - indent = " " * self.current_indent - self.write( - wrap_text( - text, - self.width, - initial_indent=indent, - subsequent_indent=indent, - preserve_paragraphs=True, - ) - ) - self.write("\n") - - def write_dl( - self, - rows: cabc.Sequence[tuple[str, str]], - col_max: int = 30, - col_spacing: int = 2, - ) -> None: - """Writes a definition list into the buffer. This is how options - and commands are usually formatted. - - :param rows: a list of two item tuples for the terms and values. - :param col_max: the maximum width of the first column. - :param col_spacing: the number of spaces between the first and - second column. - """ - rows = list(rows) - widths = measure_table(rows) - if len(widths) != 2: - raise TypeError("Expected two columns for definition list") - - first_col = min(widths[0], col_max) + col_spacing - - for first, second in iter_rows(rows, len(widths)): - self.write(f"{'':>{self.current_indent}}{first}") - if not second: - self.write("\n") - continue - if term_len(first) <= first_col - col_spacing: - self.write(" " * (first_col - term_len(first))) - else: - self.write("\n") - self.write(" " * (first_col + self.current_indent)) - - text_width = max(self.width - first_col - 2, 10) - wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) - lines = wrapped_text.splitlines() - - if lines: - self.write(f"{lines[0]}\n") - - for line in lines[1:]: - self.write(f"{'':>{first_col + self.current_indent}}{line}\n") - else: - self.write("\n") - - @contextmanager - def section(self, name: str) -> cabc.Iterator[None]: - """Helpful context manager that writes a paragraph, a heading, - and the indents. - - :param name: the section name that is written as heading. - """ - self.write_paragraph() - self.write_heading(name) - self.indent() - try: - yield - finally: - self.dedent() - - @contextmanager - def indentation(self) -> cabc.Iterator[None]: - """A context manager that increases the indentation.""" - self.indent() - try: - yield - finally: - self.dedent() - - def getvalue(self) -> str: - """Returns the buffer contents.""" - return "".join(self.buffer) - - -def join_options(options: cabc.Sequence[str]) -> tuple[str, bool]: - """Given a list of option strings this joins them in the most appropriate - way and returns them in the form ``(formatted_string, - any_prefix_is_slash)`` where the second item in the tuple is a flag that - indicates if any of the option prefixes was a slash. - """ - rv = [] - any_prefix_is_slash = False - - for opt in options: - prefix = _split_opt(opt)[0] - - if prefix == "/": - any_prefix_is_slash = True - - rv.append((len(prefix), opt)) - - rv.sort(key=lambda x: x[0]) - return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/venv/lib/python3.10/site-packages/click/globals.py b/venv/lib/python3.10/site-packages/click/globals.py deleted file mode 100644 index a2f91723d21cefdf658be327174e1f8ccdc20fcd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/globals.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -import typing as t -from threading import local - -if t.TYPE_CHECKING: - from .core import Context - -_local = local() - - -@t.overload -def get_current_context(silent: t.Literal[False] = False) -> Context: ... - - -@t.overload -def get_current_context(silent: bool = ...) -> Context | None: ... - - -def get_current_context(silent: bool = False) -> Context | None: - """Returns the current click context. This can be used as a way to - access the current context object from anywhere. This is a more implicit - alternative to the :func:`pass_context` decorator. This function is - primarily useful for helpers such as :func:`echo` which might be - interested in changing its behavior based on the current context. - - To push the current context, :meth:`Context.scope` can be used. - - .. versionadded:: 5.0 - - :param silent: if set to `True` the return value is `None` if no context - is available. The default behavior is to raise a - :exc:`RuntimeError`. - """ - try: - return t.cast("Context", _local.stack[-1]) - except (AttributeError, IndexError) as e: - if not silent: - raise RuntimeError("There is no active click context.") from e - - return None - - -def push_context(ctx: Context) -> None: - """Pushes a new context to the current stack.""" - _local.__dict__.setdefault("stack", []).append(ctx) - - -def pop_context() -> None: - """Removes the top level from the stack.""" - _local.stack.pop() - - -def resolve_color_default(color: bool | None = None) -> bool | None: - """Internal helper to get the default value of the color flag. If a - value is passed it's returned unchanged, otherwise it's looked up from - the current context. - """ - if color is not None: - return color - - ctx = get_current_context(silent=True) - - if ctx is not None: - return ctx.color - - return None diff --git a/venv/lib/python3.10/site-packages/click/parser.py b/venv/lib/python3.10/site-packages/click/parser.py deleted file mode 100644 index 1ea1f7166e4b9eac5bcb632ecd86fe0331829141..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/parser.py +++ /dev/null @@ -1,532 +0,0 @@ -""" -This module started out as largely a copy paste from the stdlib's -optparse module with the features removed that we do not need from -optparse because we implement them in Click on a higher level (for -instance type handling, help formatting and a lot more). - -The plan is to remove more and more from here over time. - -The reason this is a different module and not optparse from the stdlib -is that there are differences in 2.x and 3.x about the error messages -generated and optparse in the stdlib uses gettext for no good reason -and might cause us issues. - -Click uses parts of optparse written by Gregory P. Ward and maintained -by the Python Software Foundation. This is limited to code in parser.py. - -Copyright 2001-2006 Gregory P. Ward. All rights reserved. -Copyright 2002-2006 Python Software Foundation. All rights reserved. -""" - -# This code uses parts of optparse written by Gregory P. Ward and -# maintained by the Python Software Foundation. -# Copyright 2001-2006 Gregory P. Ward -# Copyright 2002-2006 Python Software Foundation -from __future__ import annotations - -import collections.abc as cabc -import typing as t -from collections import deque -from gettext import gettext as _ -from gettext import ngettext - -from ._utils import FLAG_NEEDS_VALUE -from ._utils import UNSET -from .exceptions import BadArgumentUsage -from .exceptions import BadOptionUsage -from .exceptions import NoSuchOption -from .exceptions import UsageError - -if t.TYPE_CHECKING: - from ._utils import T_FLAG_NEEDS_VALUE - from ._utils import T_UNSET - from .core import Argument as CoreArgument - from .core import Context - from .core import Option as CoreOption - from .core import Parameter as CoreParameter - -V = t.TypeVar("V") - - -def _unpack_args( - args: cabc.Sequence[str], nargs_spec: cabc.Sequence[int] -) -> tuple[cabc.Sequence[str | cabc.Sequence[str | None] | None], list[str]]: - """Given an iterable of arguments and an iterable of nargs specifications, - it returns a tuple with all the unpacked arguments at the first index - and all remaining arguments as the second. - - The nargs specification is the number of arguments that should be consumed - or `-1` to indicate that this position should eat up all the remainders. - - Missing items are filled with ``UNSET``. - """ - args = deque(args) - nargs_spec = deque(nargs_spec) - rv: list[str | tuple[str | T_UNSET, ...] | T_UNSET] = [] - spos: int | None = None - - def _fetch(c: deque[V]) -> V | T_UNSET: - try: - if spos is None: - return c.popleft() - else: - return c.pop() - except IndexError: - return UNSET - - while nargs_spec: - nargs = _fetch(nargs_spec) - - if nargs is None: - continue - - if nargs == 1: - rv.append(_fetch(args)) # type: ignore[arg-type] - elif nargs > 1: - x = [_fetch(args) for _ in range(nargs)] - - # If we're reversed, we're pulling in the arguments in reverse, - # so we need to turn them around. - if spos is not None: - x.reverse() - - rv.append(tuple(x)) - elif nargs < 0: - if spos is not None: - raise TypeError("Cannot have two nargs < 0") - - spos = len(rv) - rv.append(UNSET) - - # spos is the position of the wildcard (star). If it's not `None`, - # we fill it with the remainder. - if spos is not None: - rv[spos] = tuple(args) - args = [] - rv[spos + 1 :] = reversed(rv[spos + 1 :]) - - return tuple(rv), list(args) - - -def _split_opt(opt: str) -> tuple[str, str]: - first = opt[:1] - if first.isalnum(): - return "", opt - if opt[1:2] == first: - return opt[:2], opt[2:] - return first, opt[1:] - - -def _normalize_opt(opt: str, ctx: Context | None) -> str: - if ctx is None or ctx.token_normalize_func is None: - return opt - prefix, opt = _split_opt(opt) - return f"{prefix}{ctx.token_normalize_func(opt)}" - - -class _Option: - def __init__( - self, - obj: CoreOption, - opts: cabc.Sequence[str], - dest: str | None, - action: str | None = None, - nargs: int = 1, - const: t.Any | None = None, - ): - self._short_opts = [] - self._long_opts = [] - self.prefixes: set[str] = set() - - for opt in opts: - prefix, value = _split_opt(opt) - if not prefix: - raise ValueError(f"Invalid start character for option ({opt})") - self.prefixes.add(prefix[0]) - if len(prefix) == 1 and len(value) == 1: - self._short_opts.append(opt) - else: - self._long_opts.append(opt) - self.prefixes.add(prefix) - - if action is None: - action = "store" - - self.dest = dest - self.action = action - self.nargs = nargs - self.const = const - self.obj = obj - - @property - def takes_value(self) -> bool: - return self.action in ("store", "append") - - def process(self, value: t.Any, state: _ParsingState) -> None: - if self.action == "store": - state.opts[self.dest] = value # type: ignore - elif self.action == "store_const": - state.opts[self.dest] = self.const # type: ignore - elif self.action == "append": - state.opts.setdefault(self.dest, []).append(value) # type: ignore - elif self.action == "append_const": - state.opts.setdefault(self.dest, []).append(self.const) # type: ignore - elif self.action == "count": - state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore - else: - raise ValueError(f"unknown action '{self.action}'") - state.order.append(self.obj) - - -class _Argument: - def __init__(self, obj: CoreArgument, dest: str | None, nargs: int = 1): - self.dest = dest - self.nargs = nargs - self.obj = obj - - def process( - self, - value: str | cabc.Sequence[str | None] | None | T_UNSET, - state: _ParsingState, - ) -> None: - if self.nargs > 1: - assert isinstance(value, cabc.Sequence) - holes = sum(1 for x in value if x is UNSET) - if holes == len(value): - value = UNSET - elif holes != 0: - raise BadArgumentUsage( - _("Argument {name!r} takes {nargs} values.").format( - name=self.dest, nargs=self.nargs - ) - ) - - # We failed to collect any argument value so we consider the argument as unset. - if value == (): - value = UNSET - - state.opts[self.dest] = value # type: ignore - state.order.append(self.obj) - - -class _ParsingState: - def __init__(self, rargs: list[str]) -> None: - self.opts: dict[str, t.Any] = {} - self.largs: list[str] = [] - self.rargs = rargs - self.order: list[CoreParameter] = [] - - -class _OptionParser: - """The option parser is an internal class that is ultimately used to - parse options and arguments. It's modelled after optparse and brings - a similar but vastly simplified API. It should generally not be used - directly as the high level Click classes wrap it for you. - - It's not nearly as extensible as optparse or argparse as it does not - implement features that are implemented on a higher level (such as - types or defaults). - - :param ctx: optionally the :class:`~click.Context` where this parser - should go with. - - .. deprecated:: 8.2 - Will be removed in Click 9.0. - """ - - def __init__(self, ctx: Context | None = None) -> None: - #: The :class:`~click.Context` for this parser. This might be - #: `None` for some advanced use cases. - self.ctx = ctx - #: This controls how the parser deals with interspersed arguments. - #: If this is set to `False`, the parser will stop on the first - #: non-option. Click uses this to implement nested subcommands - #: safely. - self.allow_interspersed_args: bool = True - #: This tells the parser how to deal with unknown options. By - #: default it will error out (which is sensible), but there is a - #: second mode where it will ignore it and continue processing - #: after shifting all the unknown options into the resulting args. - self.ignore_unknown_options: bool = False - - if ctx is not None: - self.allow_interspersed_args = ctx.allow_interspersed_args - self.ignore_unknown_options = ctx.ignore_unknown_options - - self._short_opt: dict[str, _Option] = {} - self._long_opt: dict[str, _Option] = {} - self._opt_prefixes = {"-", "--"} - self._args: list[_Argument] = [] - - def add_option( - self, - obj: CoreOption, - opts: cabc.Sequence[str], - dest: str | None, - action: str | None = None, - nargs: int = 1, - const: t.Any | None = None, - ) -> None: - """Adds a new option named `dest` to the parser. The destination - is not inferred (unlike with optparse) and needs to be explicitly - provided. Action can be any of ``store``, ``store_const``, - ``append``, ``append_const`` or ``count``. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - opts = [_normalize_opt(opt, self.ctx) for opt in opts] - option = _Option(obj, opts, dest, action=action, nargs=nargs, const=const) - self._opt_prefixes.update(option.prefixes) - for opt in option._short_opts: - self._short_opt[opt] = option - for opt in option._long_opts: - self._long_opt[opt] = option - - def add_argument(self, obj: CoreArgument, dest: str | None, nargs: int = 1) -> None: - """Adds a positional argument named `dest` to the parser. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - self._args.append(_Argument(obj, dest=dest, nargs=nargs)) - - def parse_args( - self, args: list[str] - ) -> tuple[dict[str, t.Any], list[str], list[CoreParameter]]: - """Parses positional arguments and returns ``(values, args, order)`` - for the parsed options and arguments as well as the leftover - arguments if there are any. The order is a list of objects as they - appear on the command line. If arguments appear multiple times they - will be memorized multiple times as well. - """ - state = _ParsingState(args) - try: - self._process_args_for_options(state) - self._process_args_for_args(state) - except UsageError: - if self.ctx is None or not self.ctx.resilient_parsing: - raise - return state.opts, state.largs, state.order - - def _process_args_for_args(self, state: _ParsingState) -> None: - pargs, args = _unpack_args( - state.largs + state.rargs, [x.nargs for x in self._args] - ) - - for idx, arg in enumerate(self._args): - arg.process(pargs[idx], state) - - state.largs = args - state.rargs = [] - - def _process_args_for_options(self, state: _ParsingState) -> None: - while state.rargs: - arg = state.rargs.pop(0) - arglen = len(arg) - # Double dashes always handled explicitly regardless of what - # prefixes are valid. - if arg == "--": - return - elif arg[:1] in self._opt_prefixes and arglen > 1: - self._process_opts(arg, state) - elif self.allow_interspersed_args: - state.largs.append(arg) - else: - state.rargs.insert(0, arg) - return - - # Say this is the original argument list: - # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] - # ^ - # (we are about to process arg(i)). - # - # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of - # [arg0, ..., arg(i-1)] (any options and their arguments will have - # been removed from largs). - # - # The while loop will usually consume 1 or more arguments per pass. - # If it consumes 1 (eg. arg is an option that takes no arguments), - # then after _process_arg() is done the situation is: - # - # largs = subset of [arg0, ..., arg(i)] - # rargs = [arg(i+1), ..., arg(N-1)] - # - # If allow_interspersed_args is false, largs will always be - # *empty* -- still a subset of [arg0, ..., arg(i-1)], but - # not a very interesting subset! - - def _match_long_opt( - self, opt: str, explicit_value: str | None, state: _ParsingState - ) -> None: - if opt not in self._long_opt: - from difflib import get_close_matches - - possibilities = get_close_matches(opt, self._long_opt) - raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) - - option = self._long_opt[opt] - if option.takes_value: - # At this point it's safe to modify rargs by injecting the - # explicit value, because no exception is raised in this - # branch. This means that the inserted value will be fully - # consumed. - if explicit_value is not None: - state.rargs.insert(0, explicit_value) - - value = self._get_value_from_state(opt, option, state) - - elif explicit_value is not None: - raise BadOptionUsage( - opt, _("Option {name!r} does not take a value.").format(name=opt) - ) - - else: - value = UNSET - - option.process(value, state) - - def _match_short_opt(self, arg: str, state: _ParsingState) -> None: - stop = False - i = 1 - prefix = arg[0] - unknown_options = [] - - for ch in arg[1:]: - opt = _normalize_opt(f"{prefix}{ch}", self.ctx) - option = self._short_opt.get(opt) - i += 1 - - if not option: - if self.ignore_unknown_options: - unknown_options.append(ch) - continue - raise NoSuchOption(opt, ctx=self.ctx) - if option.takes_value: - # Any characters left in arg? Pretend they're the - # next arg, and stop consuming characters of arg. - if i < len(arg): - state.rargs.insert(0, arg[i:]) - stop = True - - value = self._get_value_from_state(opt, option, state) - - else: - value = UNSET - - option.process(value, state) - - if stop: - break - - # If we got any unknown options we recombine the string of the - # remaining options and re-attach the prefix, then report that - # to the state as new larg. This way there is basic combinatorics - # that can be achieved while still ignoring unknown arguments. - if self.ignore_unknown_options and unknown_options: - state.largs.append(f"{prefix}{''.join(unknown_options)}") - - def _get_value_from_state( - self, option_name: str, option: _Option, state: _ParsingState - ) -> str | cabc.Sequence[str] | T_FLAG_NEEDS_VALUE: - nargs = option.nargs - - value: str | cabc.Sequence[str] | T_FLAG_NEEDS_VALUE - - if len(state.rargs) < nargs: - if option.obj._flag_needs_value: - # Option allows omitting the value. - value = FLAG_NEEDS_VALUE - else: - raise BadOptionUsage( - option_name, - ngettext( - "Option {name!r} requires an argument.", - "Option {name!r} requires {nargs} arguments.", - nargs, - ).format(name=option_name, nargs=nargs), - ) - elif nargs == 1: - next_rarg = state.rargs[0] - - if ( - option.obj._flag_needs_value - and isinstance(next_rarg, str) - and next_rarg[:1] in self._opt_prefixes - and len(next_rarg) > 1 - ): - # The next arg looks like the start of an option, don't - # use it as the value if omitting the value is allowed. - value = FLAG_NEEDS_VALUE - else: - value = state.rargs.pop(0) - else: - value = tuple(state.rargs[:nargs]) - del state.rargs[:nargs] - - return value - - def _process_opts(self, arg: str, state: _ParsingState) -> None: - explicit_value = None - # Long option handling happens in two parts. The first part is - # supporting explicitly attached values. In any case, we will try - # to long match the option first. - if "=" in arg: - long_opt, explicit_value = arg.split("=", 1) - else: - long_opt = arg - norm_long_opt = _normalize_opt(long_opt, self.ctx) - - # At this point we will match the (assumed) long option through - # the long option matching code. Note that this allows options - # like "-foo" to be matched as long options. - try: - self._match_long_opt(norm_long_opt, explicit_value, state) - except NoSuchOption: - # At this point the long option matching failed, and we need - # to try with short options. However there is a special rule - # which says, that if we have a two character options prefix - # (applies to "--foo" for instance), we do not dispatch to the - # short option code and will instead raise the no option - # error. - if arg[:2] not in self._opt_prefixes: - self._match_short_opt(arg, state) - return - - if not self.ignore_unknown_options: - raise - - state.largs.append(arg) - - -def __getattr__(name: str) -> object: - import warnings - - if name in { - "OptionParser", - "Argument", - "Option", - "split_opt", - "normalize_opt", - "ParsingState", - }: - warnings.warn( - f"'parser.{name}' is deprecated and will be removed in Click 9.0." - " The old parser is available in 'optparse'.", - DeprecationWarning, - stacklevel=2, - ) - return globals()[f"_{name}"] - - if name == "split_arg_string": - from .shell_completion import split_arg_string - - warnings.warn( - "Importing 'parser.split_arg_string' is deprecated, it will only be" - " available in 'shell_completion' in Click 9.0.", - DeprecationWarning, - stacklevel=2, - ) - return split_arg_string - - raise AttributeError(name) diff --git a/venv/lib/python3.10/site-packages/click/py.typed b/venv/lib/python3.10/site-packages/click/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/click/shell_completion.py b/venv/lib/python3.10/site-packages/click/shell_completion.py deleted file mode 100644 index 8f1564c49be8e138014841d8f7cb35a34265674f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/shell_completion.py +++ /dev/null @@ -1,667 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import os -import re -import typing as t -from gettext import gettext as _ - -from .core import Argument -from .core import Command -from .core import Context -from .core import Group -from .core import Option -from .core import Parameter -from .core import ParameterSource -from .utils import echo - - -def shell_complete( - cli: Command, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - instruction: str, -) -> int: - """Perform shell completion for the given CLI program. - - :param cli: Command being called. - :param ctx_args: Extra arguments to pass to - ``cli.make_context``. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - :param instruction: Value of ``complete_var`` with the completion - instruction and shell, in the form ``instruction_shell``. - :return: Status code to exit with. - """ - shell, _, instruction = instruction.partition("_") - comp_cls = get_completion_class(shell) - - if comp_cls is None: - return 1 - - comp = comp_cls(cli, ctx_args, prog_name, complete_var) - - if instruction == "source": - echo(comp.source()) - return 0 - - if instruction == "complete": - echo(comp.complete()) - return 0 - - return 1 - - -class CompletionItem: - """Represents a completion value and metadata about the value. The - default metadata is ``type`` to indicate special shell handling, - and ``help`` if a shell supports showing a help string next to the - value. - - Arbitrary parameters can be passed when creating the object, and - accessed using ``item.attr``. If an attribute wasn't passed, - accessing it returns ``None``. - - :param value: The completion suggestion. - :param type: Tells the shell script to provide special completion - support for the type. Click uses ``"dir"`` and ``"file"``. - :param help: String shown next to the value if supported. - :param kwargs: Arbitrary metadata. The built-in implementations - don't use this, but custom type completions paired with custom - shell support could use it. - """ - - __slots__ = ("value", "type", "help", "_info") - - def __init__( - self, - value: t.Any, - type: str = "plain", - help: str | None = None, - **kwargs: t.Any, - ) -> None: - self.value: t.Any = value - self.type: str = type - self.help: str | None = help - self._info = kwargs - - def __getattr__(self, name: str) -> t.Any: - return self._info.get(name) - - -# Only Bash >= 4.4 has the nosort option. -_SOURCE_BASH = """\ -%(complete_func)s() { - local IFS=$'\\n' - local response - - response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ -%(complete_var)s=bash_complete $1) - - for completion in $response; do - IFS=',' read type value <<< "$completion" - - if [[ $type == 'dir' ]]; then - COMPREPLY=() - compopt -o dirnames - elif [[ $type == 'file' ]]; then - COMPREPLY=() - compopt -o default - elif [[ $type == 'plain' ]]; then - COMPREPLY+=($value) - fi - done - - return 0 -} - -%(complete_func)s_setup() { - complete -o nosort -F %(complete_func)s %(prog_name)s -} - -%(complete_func)s_setup; -""" - -# See ZshComplete.format_completion below, and issue #2703, before -# changing this script. -# -# (TL;DR: _describe is picky about the format, but this Zsh script snippet -# is already widely deployed. So freeze this script, and use clever-ish -# handling of colons in ZshComplet.format_completion.) -_SOURCE_ZSH = """\ -#compdef %(prog_name)s - -%(complete_func)s() { - local -a completions - local -a completions_with_descriptions - local -a response - (( ! $+commands[%(prog_name)s] )) && return 1 - - response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ -%(complete_var)s=zsh_complete %(prog_name)s)}") - - for type key descr in ${response}; do - if [[ "$type" == "plain" ]]; then - if [[ "$descr" == "_" ]]; then - completions+=("$key") - else - completions_with_descriptions+=("$key":"$descr") - fi - elif [[ "$type" == "dir" ]]; then - _path_files -/ - elif [[ "$type" == "file" ]]; then - _path_files -f - fi - done - - if [ -n "$completions_with_descriptions" ]; then - _describe -V unsorted completions_with_descriptions -U - fi - - if [ -n "$completions" ]; then - compadd -U -V unsorted -a completions - fi -} - -if [[ $zsh_eval_context[-1] == loadautofunc ]]; then - # autoload from fpath, call function directly - %(complete_func)s "$@" -else - # eval/source/. command, register function for later - compdef %(complete_func)s %(prog_name)s -fi -""" - -_SOURCE_FISH = """\ -function %(complete_func)s; - set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ -COMP_CWORD=(commandline -t) %(prog_name)s); - - for completion in $response; - set -l metadata (string split "," $completion); - - if test $metadata[1] = "dir"; - __fish_complete_directories $metadata[2]; - else if test $metadata[1] = "file"; - __fish_complete_path $metadata[2]; - else if test $metadata[1] = "plain"; - echo $metadata[2]; - end; - end; -end; - -complete --no-files --command %(prog_name)s --arguments \ -"(%(complete_func)s)"; -""" - - -class ShellComplete: - """Base class for providing shell completion support. A subclass for - a given shell will override attributes and methods to implement the - completion instructions (``source`` and ``complete``). - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - - .. versionadded:: 8.0 - """ - - name: t.ClassVar[str] - """Name to register the shell as with :func:`add_completion_class`. - This is used in completion instructions (``{name}_source`` and - ``{name}_complete``). - """ - - source_template: t.ClassVar[str] - """Completion script template formatted by :meth:`source`. This must - be provided by subclasses. - """ - - def __init__( - self, - cli: Command, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - ) -> None: - self.cli = cli - self.ctx_args = ctx_args - self.prog_name = prog_name - self.complete_var = complete_var - - @property - def func_name(self) -> str: - """The name of the shell function defined by the completion - script. - """ - safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) - return f"_{safe_name}_completion" - - def source_vars(self) -> dict[str, t.Any]: - """Vars for formatting :attr:`source_template`. - - By default this provides ``complete_func``, ``complete_var``, - and ``prog_name``. - """ - return { - "complete_func": self.func_name, - "complete_var": self.complete_var, - "prog_name": self.prog_name, - } - - def source(self) -> str: - """Produce the shell script that defines the completion - function. By default this ``%``-style formats - :attr:`source_template` with the dict returned by - :meth:`source_vars`. - """ - return self.source_template % self.source_vars() - - def get_completion_args(self) -> tuple[list[str], str]: - """Use the env vars defined by the shell script to return a - tuple of ``args, incomplete``. This must be implemented by - subclasses. - """ - raise NotImplementedError - - def get_completions(self, args: list[str], incomplete: str) -> list[CompletionItem]: - """Determine the context and last complete command or parameter - from the complete args. Call that object's ``shell_complete`` - method to get the completions for the incomplete value. - - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) - obj, incomplete = _resolve_incomplete(ctx, args, incomplete) - return obj.shell_complete(ctx, incomplete) - - def format_completion(self, item: CompletionItem) -> str: - """Format a completion item into the form recognized by the - shell script. This must be implemented by subclasses. - - :param item: Completion item to format. - """ - raise NotImplementedError - - def complete(self) -> str: - """Produce the completion data to send back to the shell. - - By default this calls :meth:`get_completion_args`, gets the - completions, then calls :meth:`format_completion` for each - completion. - """ - args, incomplete = self.get_completion_args() - completions = self.get_completions(args, incomplete) - out = [self.format_completion(item) for item in completions] - return "\n".join(out) - - -class BashComplete(ShellComplete): - """Shell completion for Bash.""" - - name = "bash" - source_template = _SOURCE_BASH - - @staticmethod - def _check_version() -> None: - import shutil - import subprocess - - bash_exe = shutil.which("bash") - - if bash_exe is None: - match = None - else: - output = subprocess.run( - [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], - stdout=subprocess.PIPE, - ) - match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) - - if match is not None: - major, minor = match.groups() - - if major < "4" or major == "4" and minor < "4": - echo( - _( - "Shell completion is not supported for Bash" - " versions older than 4.4." - ), - err=True, - ) - else: - echo( - _("Couldn't detect Bash version, shell completion is not supported."), - err=True, - ) - - def source(self) -> str: - self._check_version() - return super().source() - - def get_completion_args(self) -> tuple[list[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - return f"{item.type},{item.value}" - - -class ZshComplete(ShellComplete): - """Shell completion for Zsh.""" - - name = "zsh" - source_template = _SOURCE_ZSH - - def get_completion_args(self) -> tuple[list[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - help_ = item.help or "_" - # The zsh completion script uses `_describe` on items with help - # texts (which splits the item help from the item value at the - # first unescaped colon) and `compadd` on items without help - # text (which uses the item value as-is and does not support - # colon escaping). So escape colons in the item value if and - # only if the item help is not the sentinel "_" value, as used - # by the completion script. - # - # (The zsh completion script is potentially widely deployed, and - # thus harder to fix than this method.) - # - # See issue #1812 and issue #2703 for further context. - value = item.value.replace(":", r"\:") if help_ != "_" else item.value - return f"{item.type}\n{value}\n{help_}" - - -class FishComplete(ShellComplete): - """Shell completion for Fish.""" - - name = "fish" - source_template = _SOURCE_FISH - - def get_completion_args(self) -> tuple[list[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - incomplete = os.environ["COMP_CWORD"] - if incomplete: - incomplete = split_arg_string(incomplete)[0] - args = cwords[1:] - - # Fish stores the partial word in both COMP_WORDS and - # COMP_CWORD, remove it from complete args. - if incomplete and args and args[-1] == incomplete: - args.pop() - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - if item.help: - return f"{item.type},{item.value}\t{item.help}" - - return f"{item.type},{item.value}" - - -ShellCompleteType = t.TypeVar("ShellCompleteType", bound="type[ShellComplete]") - - -_available_shells: dict[str, type[ShellComplete]] = { - "bash": BashComplete, - "fish": FishComplete, - "zsh": ZshComplete, -} - - -def add_completion_class( - cls: ShellCompleteType, name: str | None = None -) -> ShellCompleteType: - """Register a :class:`ShellComplete` subclass under the given name. - The name will be provided by the completion instruction environment - variable during completion. - - :param cls: The completion class that will handle completion for the - shell. - :param name: Name to register the class under. Defaults to the - class's ``name`` attribute. - """ - if name is None: - name = cls.name - - _available_shells[name] = cls - - return cls - - -def get_completion_class(shell: str) -> type[ShellComplete] | None: - """Look up a registered :class:`ShellComplete` subclass by the name - provided by the completion instruction environment variable. If the - name isn't registered, returns ``None``. - - :param shell: Name the class is registered under. - """ - return _available_shells.get(shell) - - -def split_arg_string(string: str) -> list[str]: - """Split an argument string as with :func:`shlex.split`, but don't - fail if the string is incomplete. Ignores a missing closing quote or - incomplete escape sequence and uses the partial token as-is. - - .. code-block:: python - - split_arg_string("example 'my file") - ["example", "my file"] - - split_arg_string("example my\\") - ["example", "my"] - - :param string: String to split. - - .. versionchanged:: 8.2 - Moved to ``shell_completion`` from ``parser``. - """ - import shlex - - lex = shlex.shlex(string, posix=True) - lex.whitespace_split = True - lex.commenters = "" - out = [] - - try: - for token in lex: - out.append(token) - except ValueError: - # Raised when end-of-string is reached in an invalid state. Use - # the partial token as-is. The quote or escape character is in - # lex.state, not lex.token. - out.append(lex.token) - - return out - - -def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: - """Determine if the given parameter is an argument that can still - accept values. - - :param ctx: Invocation context for the command represented by the - parsed complete args. - :param param: Argument object being checked. - """ - if not isinstance(param, Argument): - return False - - assert param.name is not None - # Will be None if expose_value is False. - value = ctx.params.get(param.name) - return ( - param.nargs == -1 - or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE - or ( - param.nargs > 1 - and isinstance(value, (tuple, list)) - and len(value) < param.nargs - ) - ) - - -def _start_of_option(ctx: Context, value: str) -> bool: - """Check if the value looks like the start of an option.""" - if not value: - return False - - c = value[0] - return c in ctx._opt_prefixes - - -def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool: - """Determine if the given parameter is an option that needs a value. - - :param args: List of complete args before the incomplete value. - :param param: Option object being checked. - """ - if not isinstance(param, Option): - return False - - if param.is_flag or param.count: - return False - - last_option = None - - for index, arg in enumerate(reversed(args)): - if index + 1 > param.nargs: - break - - if _start_of_option(ctx, arg): - last_option = arg - break - - return last_option is not None and last_option in param.opts - - -def _resolve_context( - cli: Command, - ctx_args: cabc.MutableMapping[str, t.Any], - prog_name: str, - args: list[str], -) -> Context: - """Produce the context hierarchy starting with the command and - traversing the complete arguments. This only follows the commands, - it doesn't trigger input prompts or callbacks. - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param args: List of complete args before the incomplete value. - """ - ctx_args["resilient_parsing"] = True - with cli.make_context(prog_name, args.copy(), **ctx_args) as ctx: - args = ctx._protected_args + ctx.args - - while args: - command = ctx.command - - if isinstance(command, Group): - if not command.chain: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - with cmd.make_context( - name, args, parent=ctx, resilient_parsing=True - ) as sub_ctx: - ctx = sub_ctx - args = ctx._protected_args + ctx.args - else: - sub_ctx = ctx - - while args: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - with cmd.make_context( - name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - resilient_parsing=True, - ) as sub_sub_ctx: - sub_ctx = sub_sub_ctx - args = sub_ctx.args - - ctx = sub_ctx - args = [*sub_ctx._protected_args, *sub_ctx.args] - else: - break - - return ctx - - -def _resolve_incomplete( - ctx: Context, args: list[str], incomplete: str -) -> tuple[Command | Parameter, str]: - """Find the Click object that will handle the completion of the - incomplete value. Return the object and the incomplete value. - - :param ctx: Invocation context for the command represented by - the parsed complete args. - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - # Different shells treat an "=" between a long option name and - # value differently. Might keep the value joined, return the "=" - # as a separate item, or return the split name and value. Always - # split and discard the "=" to make completion easier. - if incomplete == "=": - incomplete = "" - elif "=" in incomplete and _start_of_option(ctx, incomplete): - name, _, incomplete = incomplete.partition("=") - args.append(name) - - # The "--" marker tells Click to stop treating values as options - # even if they start with the option character. If it hasn't been - # given and the incomplete arg looks like an option, the current - # command will provide option name completions. - if "--" not in args and _start_of_option(ctx, incomplete): - return ctx.command, incomplete - - params = ctx.command.get_params(ctx) - - # If the last complete arg is an option name with an incomplete - # value, the option will provide value completions. - for param in params: - if _is_incomplete_option(ctx, args, param): - return param, incomplete - - # It's not an option name or value. The first argument without a - # parsed value will provide value completions. - for param in params: - if _is_incomplete_argument(ctx, param): - return param, incomplete - - # There were no unparsed arguments, the command may be a group that - # will provide command name completions. - return ctx.command, incomplete diff --git a/venv/lib/python3.10/site-packages/click/termui.py b/venv/lib/python3.10/site-packages/click/termui.py deleted file mode 100644 index 2e98a0771ca410a7a2ed83199cf401e75cc6d41f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/termui.py +++ /dev/null @@ -1,883 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import inspect -import io -import itertools -import sys -import typing as t -from contextlib import AbstractContextManager -from gettext import gettext as _ - -from ._compat import isatty -from ._compat import strip_ansi -from .exceptions import Abort -from .exceptions import UsageError -from .globals import resolve_color_default -from .types import Choice -from .types import convert_type -from .types import ParamType -from .utils import echo -from .utils import LazyFile - -if t.TYPE_CHECKING: - from ._termui_impl import ProgressBar - -V = t.TypeVar("V") - -# The prompt functions to use. The doc tools currently override these -# functions to customize how they work. -visible_prompt_func: t.Callable[[str], str] = input - -_ansi_colors = { - "black": 30, - "red": 31, - "green": 32, - "yellow": 33, - "blue": 34, - "magenta": 35, - "cyan": 36, - "white": 37, - "reset": 39, - "bright_black": 90, - "bright_red": 91, - "bright_green": 92, - "bright_yellow": 93, - "bright_blue": 94, - "bright_magenta": 95, - "bright_cyan": 96, - "bright_white": 97, -} -_ansi_reset_all = "\033[0m" - - -def hidden_prompt_func(prompt: str) -> str: - import getpass - - return getpass.getpass(prompt) - - -def _build_prompt( - text: str, - suffix: str, - show_default: bool = False, - default: t.Any | None = None, - show_choices: bool = True, - type: ParamType | None = None, -) -> str: - prompt = text - if type is not None and show_choices and isinstance(type, Choice): - prompt += f" ({', '.join(map(str, type.choices))})" - if default is not None and show_default: - prompt = f"{prompt} [{_format_default(default)}]" - return f"{prompt}{suffix}" - - -def _format_default(default: t.Any) -> t.Any: - if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): - return default.name - - return default - - -def prompt( - text: str, - default: t.Any | None = None, - hide_input: bool = False, - confirmation_prompt: bool | str = False, - type: ParamType | t.Any | None = None, - value_proc: t.Callable[[str], t.Any] | None = None, - prompt_suffix: str = ": ", - show_default: bool = True, - err: bool = False, - show_choices: bool = True, -) -> t.Any: - """Prompts a user for input. This is a convenience function that can - be used to prompt a user for input later. - - If the user aborts the input by sending an interrupt signal, this - function will catch it and raise a :exc:`Abort` exception. - - :param text: the text to show for the prompt. - :param default: the default value to use if no input happens. If this - is not given it will prompt until it's aborted. - :param hide_input: if this is set to true then the input value will - be hidden. - :param confirmation_prompt: Prompt a second time to confirm the - value. Can be set to a string instead of ``True`` to customize - the message. - :param type: the type to use to check the value against. - :param value_proc: if this parameter is provided it's a function that - is invoked instead of the type conversion to - convert a value. - :param prompt_suffix: a suffix that should be added to the prompt. - :param show_default: shows or hides the default value in the prompt. - :param err: if set to true the file defaults to ``stderr`` instead of - ``stdout``, the same as with echo. - :param show_choices: Show or hide choices if the passed type is a Choice. - For example if type is a Choice of either day or week, - show_choices is true and text is "Group by" then the - prompt will be "Group by (day, week): ". - - .. versionchanged:: 8.3.1 - A space is no longer appended to the prompt. - - .. versionadded:: 8.0 - ``confirmation_prompt`` can be a custom string. - - .. versionadded:: 7.0 - Added the ``show_choices`` parameter. - - .. versionadded:: 6.0 - Added unicode support for cmd.exe on Windows. - - .. versionadded:: 4.0 - Added the `err` parameter. - - """ - - def prompt_func(text: str) -> str: - f = hidden_prompt_func if hide_input else visible_prompt_func - try: - # Write the prompt separately so that we get nice - # coloring through colorama on Windows - echo(text[:-1], nl=False, err=err) - # Echo the last character to stdout to work around an issue where - # readline causes backspace to clear the whole line. - return f(text[-1:]) - except (KeyboardInterrupt, EOFError): - # getpass doesn't print a newline if the user aborts input with ^C. - # Allegedly this behavior is inherited from getpass(3). - # A doc bug has been filed at https://bugs.python.org/issue24711 - if hide_input: - echo(None, err=err) - raise Abort() from None - - if value_proc is None: - value_proc = convert_type(type, default) - - prompt = _build_prompt( - text, prompt_suffix, show_default, default, show_choices, type - ) - - if confirmation_prompt: - if confirmation_prompt is True: - confirmation_prompt = _("Repeat for confirmation") - - confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) - - while True: - while True: - value = prompt_func(prompt) - if value: - break - elif default is not None: - value = default - break - try: - result = value_proc(value) - except UsageError as e: - if hide_input: - echo(_("Error: The value you entered was invalid."), err=err) - else: - echo(_("Error: {e.message}").format(e=e), err=err) - continue - if not confirmation_prompt: - return result - while True: - value2 = prompt_func(confirmation_prompt) - is_empty = not value and not value2 - if value2 or is_empty: - break - if value == value2: - return result - echo(_("Error: The two entered values do not match."), err=err) - - -def confirm( - text: str, - default: bool | None = False, - abort: bool = False, - prompt_suffix: str = ": ", - show_default: bool = True, - err: bool = False, -) -> bool: - """Prompts for confirmation (yes/no question). - - If the user aborts the input by sending a interrupt signal this - function will catch it and raise a :exc:`Abort` exception. - - :param text: the question to ask. - :param default: The default value to use when no input is given. If - ``None``, repeat until input is given. - :param abort: if this is set to `True` a negative answer aborts the - exception by raising :exc:`Abort`. - :param prompt_suffix: a suffix that should be added to the prompt. - :param show_default: shows or hides the default value in the prompt. - :param err: if set to true the file defaults to ``stderr`` instead of - ``stdout``, the same as with echo. - - .. versionchanged:: 8.3.1 - A space is no longer appended to the prompt. - - .. versionchanged:: 8.0 - Repeat until input is given if ``default`` is ``None``. - - .. versionadded:: 4.0 - Added the ``err`` parameter. - """ - prompt = _build_prompt( - text, - prompt_suffix, - show_default, - "y/n" if default is None else ("Y/n" if default else "y/N"), - ) - - while True: - try: - # Write the prompt separately so that we get nice - # coloring through colorama on Windows - echo(prompt[:-1], nl=False, err=err) - # Echo the last character to stdout to work around an issue where - # readline causes backspace to clear the whole line. - value = visible_prompt_func(prompt[-1:]).lower().strip() - except (KeyboardInterrupt, EOFError): - raise Abort() from None - if value in ("y", "yes"): - rv = True - elif value in ("n", "no"): - rv = False - elif default is not None and value == "": - rv = default - else: - echo(_("Error: invalid input"), err=err) - continue - break - if abort and not rv: - raise Abort() - return rv - - -def echo_via_pager( - text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str, - color: bool | None = None, -) -> None: - """This function takes a text and shows it via an environment specific - pager on stdout. - - .. versionchanged:: 3.0 - Added the `color` flag. - - :param text_or_generator: the text to page, or alternatively, a - generator emitting the text to page. - :param color: controls if the pager supports ANSI colors or not. The - default is autodetection. - """ - color = resolve_color_default(color) - - if inspect.isgeneratorfunction(text_or_generator): - i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)() - elif isinstance(text_or_generator, str): - i = [text_or_generator] - else: - i = iter(t.cast("cabc.Iterable[str]", text_or_generator)) - - # convert every element of i to a text type if necessary - text_generator = (el if isinstance(el, str) else str(el) for el in i) - - from ._termui_impl import pager - - return pager(itertools.chain(text_generator, "\n"), color) - - -@t.overload -def progressbar( - *, - length: int, - label: str | None = None, - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, -) -> ProgressBar[int]: ... - - -@t.overload -def progressbar( - iterable: cabc.Iterable[V] | None = None, - length: int | None = None, - label: str | None = None, - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - item_show_func: t.Callable[[V | None], str | None] | None = None, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, -) -> ProgressBar[V]: ... - - -def progressbar( - iterable: cabc.Iterable[V] | None = None, - length: int | None = None, - label: str | None = None, - hidden: bool = False, - show_eta: bool = True, - show_percent: bool | None = None, - show_pos: bool = False, - item_show_func: t.Callable[[V | None], str | None] | None = None, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.TextIO | None = None, - color: bool | None = None, - update_min_steps: int = 1, -) -> ProgressBar[V]: - """This function creates an iterable context manager that can be used - to iterate over something while showing a progress bar. It will - either iterate over the `iterable` or `length` items (that are counted - up). While iteration happens, this function will print a rendered - progress bar to the given `file` (defaults to stdout) and will attempt - to calculate remaining time and more. By default, this progress bar - will not be rendered if the file is not a terminal. - - The context manager creates the progress bar. When the context - manager is entered the progress bar is already created. With every - iteration over the progress bar, the iterable passed to the bar is - advanced and the bar is updated. When the context manager exits, - a newline is printed and the progress bar is finalized on screen. - - Note: The progress bar is currently designed for use cases where the - total progress can be expected to take at least several seconds. - Because of this, the ProgressBar class object won't display - progress that is considered too fast, and progress where the time - between steps is less than a second. - - No printing must happen or the progress bar will be unintentionally - destroyed. - - Example usage:: - - with progressbar(items) as bar: - for item in bar: - do_something_with(item) - - Alternatively, if no iterable is specified, one can manually update the - progress bar through the `update()` method instead of directly - iterating over the progress bar. The update method accepts the number - of steps to increment the bar with:: - - with progressbar(length=chunks.total_bytes) as bar: - for chunk in chunks: - process_chunk(chunk) - bar.update(chunks.bytes) - - The ``update()`` method also takes an optional value specifying the - ``current_item`` at the new position. This is useful when used - together with ``item_show_func`` to customize the output for each - manual step:: - - with click.progressbar( - length=total_size, - label='Unzipping archive', - item_show_func=lambda a: a.filename - ) as bar: - for archive in zip_file: - archive.extract() - bar.update(archive.size, archive) - - :param iterable: an iterable to iterate over. If not provided the length - is required. - :param length: the number of items to iterate over. By default the - progressbar will attempt to ask the iterator about its - length, which might or might not work. If an iterable is - also provided this parameter can be used to override the - length. If an iterable is not provided the progress bar - will iterate over a range of that length. - :param label: the label to show next to the progress bar. - :param hidden: hide the progressbar. Defaults to ``False``. When no tty is - detected, it will only print the progressbar label. Setting this to - ``False`` also disables that. - :param show_eta: enables or disables the estimated time display. This is - automatically disabled if the length cannot be - determined. - :param show_percent: enables or disables the percentage display. The - default is `True` if the iterable has a length or - `False` if not. - :param show_pos: enables or disables the absolute position display. The - default is `False`. - :param item_show_func: A function called with the current item which - can return a string to show next to the progress bar. If the - function returns ``None`` nothing is shown. The current item can - be ``None``, such as when entering and exiting the bar. - :param fill_char: the character to use to show the filled part of the - progress bar. - :param empty_char: the character to use to show the non-filled part of - the progress bar. - :param bar_template: the format string to use as template for the bar. - The parameters in it are ``label`` for the label, - ``bar`` for the progress bar and ``info`` for the - info section. - :param info_sep: the separator between multiple info items (eta etc.) - :param width: the width of the progress bar in characters, 0 means full - terminal width - :param file: The file to write to. If this is not a terminal then - only the label is printed. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are included anywhere in the progress bar output - which is not the case by default. - :param update_min_steps: Render only when this many updates have - completed. This allows tuning for very fast iterators. - - .. versionadded:: 8.2 - The ``hidden`` argument. - - .. versionchanged:: 8.0 - Output is shown even if execution time is less than 0.5 seconds. - - .. versionchanged:: 8.0 - ``item_show_func`` shows the current item, not the previous one. - - .. versionchanged:: 8.0 - Labels are echoed if the output is not a TTY. Reverts a change - in 7.0 that removed all output. - - .. versionadded:: 8.0 - The ``update_min_steps`` parameter. - - .. versionadded:: 4.0 - The ``color`` parameter and ``update`` method. - - .. versionadded:: 2.0 - """ - from ._termui_impl import ProgressBar - - color = resolve_color_default(color) - return ProgressBar( - iterable=iterable, - length=length, - hidden=hidden, - show_eta=show_eta, - show_percent=show_percent, - show_pos=show_pos, - item_show_func=item_show_func, - fill_char=fill_char, - empty_char=empty_char, - bar_template=bar_template, - info_sep=info_sep, - file=file, - label=label, - width=width, - color=color, - update_min_steps=update_min_steps, - ) - - -def clear() -> None: - """Clears the terminal screen. This will have the effect of clearing - the whole visible space of the terminal and moving the cursor to the - top left. This does not do anything if not connected to a terminal. - - .. versionadded:: 2.0 - """ - if not isatty(sys.stdout): - return - - # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor - echo("\033[2J\033[1;1H", nl=False) - - -def _interpret_color(color: int | tuple[int, int, int] | str, offset: int = 0) -> str: - if isinstance(color, int): - return f"{38 + offset};5;{color:d}" - - if isinstance(color, (tuple, list)): - r, g, b = color - return f"{38 + offset};2;{r:d};{g:d};{b:d}" - - return str(_ansi_colors[color] + offset) - - -def style( - text: t.Any, - fg: int | tuple[int, int, int] | str | None = None, - bg: int | tuple[int, int, int] | str | None = None, - bold: bool | None = None, - dim: bool | None = None, - underline: bool | None = None, - overline: bool | None = None, - italic: bool | None = None, - blink: bool | None = None, - reverse: bool | None = None, - strikethrough: bool | None = None, - reset: bool = True, -) -> str: - """Styles a text with ANSI styles and returns the new string. By - default the styling is self contained which means that at the end - of the string a reset code is issued. This can be prevented by - passing ``reset=False``. - - Examples:: - - click.echo(click.style('Hello World!', fg='green')) - click.echo(click.style('ATTENTION!', blink=True)) - click.echo(click.style('Some things', reverse=True, fg='cyan')) - click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) - - Supported color names: - - * ``black`` (might be a gray) - * ``red`` - * ``green`` - * ``yellow`` (might be an orange) - * ``blue`` - * ``magenta`` - * ``cyan`` - * ``white`` (might be light gray) - * ``bright_black`` - * ``bright_red`` - * ``bright_green`` - * ``bright_yellow`` - * ``bright_blue`` - * ``bright_magenta`` - * ``bright_cyan`` - * ``bright_white`` - * ``reset`` (reset the color code only) - - If the terminal supports it, color may also be specified as: - - - An integer in the interval [0, 255]. The terminal must support - 8-bit/256-color mode. - - An RGB tuple of three integers in [0, 255]. The terminal must - support 24-bit/true-color mode. - - See https://en.wikipedia.org/wiki/ANSI_color and - https://gist.github.com/XVilka/8346728 for more information. - - :param text: the string to style with ansi codes. - :param fg: if provided this will become the foreground color. - :param bg: if provided this will become the background color. - :param bold: if provided this will enable or disable bold mode. - :param dim: if provided this will enable or disable dim mode. This is - badly supported. - :param underline: if provided this will enable or disable underline. - :param overline: if provided this will enable or disable overline. - :param italic: if provided this will enable or disable italic. - :param blink: if provided this will enable or disable blinking. - :param reverse: if provided this will enable or disable inverse - rendering (foreground becomes background and the - other way round). - :param strikethrough: if provided this will enable or disable - striking through text. - :param reset: by default a reset-all code is added at the end of the - string which means that styles do not carry over. This - can be disabled to compose styles. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. - - .. versionchanged:: 8.0 - Added support for 256 and RGB color codes. - - .. versionchanged:: 8.0 - Added the ``strikethrough``, ``italic``, and ``overline`` - parameters. - - .. versionchanged:: 7.0 - Added support for bright colors. - - .. versionadded:: 2.0 - """ - if not isinstance(text, str): - text = str(text) - - bits = [] - - if fg: - try: - bits.append(f"\033[{_interpret_color(fg)}m") - except KeyError: - raise TypeError(f"Unknown color {fg!r}") from None - - if bg: - try: - bits.append(f"\033[{_interpret_color(bg, 10)}m") - except KeyError: - raise TypeError(f"Unknown color {bg!r}") from None - - if bold is not None: - bits.append(f"\033[{1 if bold else 22}m") - if dim is not None: - bits.append(f"\033[{2 if dim else 22}m") - if underline is not None: - bits.append(f"\033[{4 if underline else 24}m") - if overline is not None: - bits.append(f"\033[{53 if overline else 55}m") - if italic is not None: - bits.append(f"\033[{3 if italic else 23}m") - if blink is not None: - bits.append(f"\033[{5 if blink else 25}m") - if reverse is not None: - bits.append(f"\033[{7 if reverse else 27}m") - if strikethrough is not None: - bits.append(f"\033[{9 if strikethrough else 29}m") - bits.append(text) - if reset: - bits.append(_ansi_reset_all) - return "".join(bits) - - -def unstyle(text: str) -> str: - """Removes ANSI styling information from a string. Usually it's not - necessary to use this function as Click's echo function will - automatically remove styling if necessary. - - .. versionadded:: 2.0 - - :param text: the text to remove style information from. - """ - return strip_ansi(text) - - -def secho( - message: t.Any | None = None, - file: t.IO[t.AnyStr] | None = None, - nl: bool = True, - err: bool = False, - color: bool | None = None, - **styles: t.Any, -) -> None: - """This function combines :func:`echo` and :func:`style` into one - call. As such the following two calls are the same:: - - click.secho('Hello World!', fg='green') - click.echo(click.style('Hello World!', fg='green')) - - All keyword arguments are forwarded to the underlying functions - depending on which one they go with. - - Non-string types will be converted to :class:`str`. However, - :class:`bytes` are passed directly to :meth:`echo` without applying - style. If you want to style bytes that represent text, call - :meth:`bytes.decode` first. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. Bytes are - passed through without style applied. - - .. versionadded:: 2.0 - """ - if message is not None and not isinstance(message, (bytes, bytearray)): - message = style(message, **styles) - - return echo(message, file=file, nl=nl, err=err, color=color) - - -@t.overload -def edit( - text: bytes | bytearray, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = False, - extension: str = ".txt", -) -> bytes | None: ... - - -@t.overload -def edit( - text: str, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", -) -> str | None: ... - - -@t.overload -def edit( - text: None = None, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", - filename: str | cabc.Iterable[str] | None = None, -) -> None: ... - - -def edit( - text: str | bytes | bytearray | None = None, - editor: str | None = None, - env: cabc.Mapping[str, str] | None = None, - require_save: bool = True, - extension: str = ".txt", - filename: str | cabc.Iterable[str] | None = None, -) -> str | bytes | bytearray | None: - r"""Edits the given text in the defined editor. If an editor is given - (should be the full path to the executable but the regular operating - system search path is used for finding the executable) it overrides - the detected editor. Optionally, some environment variables can be - used. If the editor is closed without changes, `None` is returned. In - case a file is edited directly the return value is always `None` and - `require_save` and `extension` are ignored. - - If the editor cannot be opened a :exc:`UsageError` is raised. - - Note for Windows: to simplify cross-platform usage, the newlines are - automatically converted from POSIX to Windows and vice versa. As such, - the message here will have ``\n`` as newline markers. - - :param text: the text to edit. - :param editor: optionally the editor to use. Defaults to automatic - detection. - :param env: environment variables to forward to the editor. - :param require_save: if this is true, then not saving in the editor - will make the return value become `None`. - :param extension: the extension to tell the editor about. This defaults - to `.txt` but changing this might change syntax - highlighting. - :param filename: if provided it will edit this file instead of the - provided text contents. It will not use a temporary - file as an indirection in that case. If the editor supports - editing multiple files at once, a sequence of files may be - passed as well. Invoke `click.file` once per file instead - if multiple files cannot be managed at once or editing the - files serially is desired. - - .. versionchanged:: 8.2.0 - ``filename`` now accepts any ``Iterable[str]`` in addition to a ``str`` - if the ``editor`` supports editing multiple files at once. - - """ - from ._termui_impl import Editor - - ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) - - if filename is None: - return ed.edit(text) - - if isinstance(filename, str): - filename = (filename,) - - ed.edit_files(filenames=filename) - return None - - -def launch(url: str, wait: bool = False, locate: bool = False) -> int: - """This function launches the given URL (or filename) in the default - viewer application for this file type. If this is an executable, it - might launch the executable in a new session. The return value is - the exit code of the launched application. Usually, ``0`` indicates - success. - - Examples:: - - click.launch('https://click.palletsprojects.com/') - click.launch('/my/downloaded/file', locate=True) - - .. versionadded:: 2.0 - - :param url: URL or filename of the thing to launch. - :param wait: Wait for the program to exit before returning. This - only works if the launched program blocks. In particular, - ``xdg-open`` on Linux does not block. - :param locate: if this is set to `True` then instead of launching the - application associated with the URL it will attempt to - launch a file manager with the file located. This - might have weird effects if the URL does not point to - the filesystem. - """ - from ._termui_impl import open_url - - return open_url(url, wait=wait, locate=locate) - - -# If this is provided, getchar() calls into this instead. This is used -# for unittesting purposes. -_getchar: t.Callable[[bool], str] | None = None - - -def getchar(echo: bool = False) -> str: - """Fetches a single character from the terminal and returns it. This - will always return a unicode character and under certain rare - circumstances this might return more than one character. The - situations which more than one character is returned is when for - whatever reason multiple characters end up in the terminal buffer or - standard input was not actually a terminal. - - Note that this will always read from the terminal, even if something - is piped into the standard input. - - Note for Windows: in rare cases when typing non-ASCII characters, this - function might wait for a second character and then return both at once. - This is because certain Unicode characters look like special-key markers. - - .. versionadded:: 2.0 - - :param echo: if set to `True`, the character read will also show up on - the terminal. The default is to not show it. - """ - global _getchar - - if _getchar is None: - from ._termui_impl import getchar as f - - _getchar = f - - return _getchar(echo) - - -def raw_terminal() -> AbstractContextManager[int]: - from ._termui_impl import raw_terminal as f - - return f() - - -def pause(info: str | None = None, err: bool = False) -> None: - """This command stops execution and waits for the user to press any - key to continue. This is similar to the Windows batch "pause" - command. If the program is not run through a terminal, this command - will instead do nothing. - - .. versionadded:: 2.0 - - .. versionadded:: 4.0 - Added the `err` parameter. - - :param info: The message to print before pausing. Defaults to - ``"Press any key to continue..."``. - :param err: if set to message goes to ``stderr`` instead of - ``stdout``, the same as with echo. - """ - if not isatty(sys.stdin) or not isatty(sys.stdout): - return - - if info is None: - info = _("Press any key to continue...") - - try: - if info: - echo(info, nl=False, err=err) - try: - getchar() - except (KeyboardInterrupt, EOFError): - pass - finally: - if info: - echo(err=err) diff --git a/venv/lib/python3.10/site-packages/click/testing.py b/venv/lib/python3.10/site-packages/click/testing.py deleted file mode 100644 index f6f60b809a065e2d67de5a7ec13d9d3c51b5e760..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/testing.py +++ /dev/null @@ -1,577 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import contextlib -import io -import os -import shlex -import sys -import tempfile -import typing as t -from types import TracebackType - -from . import _compat -from . import formatting -from . import termui -from . import utils -from ._compat import _find_binary_reader - -if t.TYPE_CHECKING: - from _typeshed import ReadableBuffer - - from .core import Command - - -class EchoingStdin: - def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: - self._input = input - self._output = output - self._paused = False - - def __getattr__(self, x: str) -> t.Any: - return getattr(self._input, x) - - def _echo(self, rv: bytes) -> bytes: - if not self._paused: - self._output.write(rv) - - return rv - - def read(self, n: int = -1) -> bytes: - return self._echo(self._input.read(n)) - - def read1(self, n: int = -1) -> bytes: - return self._echo(self._input.read1(n)) # type: ignore - - def readline(self, n: int = -1) -> bytes: - return self._echo(self._input.readline(n)) - - def readlines(self) -> list[bytes]: - return [self._echo(x) for x in self._input.readlines()] - - def __iter__(self) -> cabc.Iterator[bytes]: - return iter(self._echo(x) for x in self._input) - - def __repr__(self) -> str: - return repr(self._input) - - -@contextlib.contextmanager -def _pause_echo(stream: EchoingStdin | None) -> cabc.Iterator[None]: - if stream is None: - yield - else: - stream._paused = True - yield - stream._paused = False - - -class BytesIOCopy(io.BytesIO): - """Patch ``io.BytesIO`` to let the written stream be copied to another. - - .. versionadded:: 8.2 - """ - - def __init__(self, copy_to: io.BytesIO) -> None: - super().__init__() - self.copy_to = copy_to - - def flush(self) -> None: - super().flush() - self.copy_to.flush() - - def write(self, b: ReadableBuffer) -> int: - self.copy_to.write(b) - return super().write(b) - - -class StreamMixer: - """Mixes `` and `` streams. - - The result is available in the ``output`` attribute. - - .. versionadded:: 8.2 - """ - - def __init__(self) -> None: - self.output: io.BytesIO = io.BytesIO() - self.stdout: io.BytesIO = BytesIOCopy(copy_to=self.output) - self.stderr: io.BytesIO = BytesIOCopy(copy_to=self.output) - - def __del__(self) -> None: - """ - Guarantee that embedded file-like objects are closed in a - predictable order, protecting against races between - self.output being closed and other streams being flushed on close - - .. versionadded:: 8.2.2 - """ - self.stderr.close() - self.stdout.close() - self.output.close() - - -class _NamedTextIOWrapper(io.TextIOWrapper): - def __init__( - self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any - ) -> None: - super().__init__(buffer, **kwargs) - self._name = name - self._mode = mode - - @property - def name(self) -> str: - return self._name - - @property - def mode(self) -> str: - return self._mode - - -def make_input_stream( - input: str | bytes | t.IO[t.Any] | None, charset: str -) -> t.BinaryIO: - # Is already an input stream. - if hasattr(input, "read"): - rv = _find_binary_reader(t.cast("t.IO[t.Any]", input)) - - if rv is not None: - return rv - - raise TypeError("Could not find binary reader for input stream.") - - if input is None: - input = b"" - elif isinstance(input, str): - input = input.encode(charset) - - return io.BytesIO(input) - - -class Result: - """Holds the captured result of an invoked CLI script. - - :param runner: The runner that created the result - :param stdout_bytes: The standard output as bytes. - :param stderr_bytes: The standard error as bytes. - :param output_bytes: A mix of ``stdout_bytes`` and ``stderr_bytes``, as the - user would see it in its terminal. - :param return_value: The value returned from the invoked command. - :param exit_code: The exit code as integer. - :param exception: The exception that happened if one did. - :param exc_info: Exception information (exception type, exception instance, - traceback type). - - .. versionchanged:: 8.2 - ``stderr_bytes`` no longer optional, ``output_bytes`` introduced and - ``mix_stderr`` has been removed. - - .. versionadded:: 8.0 - Added ``return_value``. - """ - - def __init__( - self, - runner: CliRunner, - stdout_bytes: bytes, - stderr_bytes: bytes, - output_bytes: bytes, - return_value: t.Any, - exit_code: int, - exception: BaseException | None, - exc_info: tuple[type[BaseException], BaseException, TracebackType] - | None = None, - ): - self.runner = runner - self.stdout_bytes = stdout_bytes - self.stderr_bytes = stderr_bytes - self.output_bytes = output_bytes - self.return_value = return_value - self.exit_code = exit_code - self.exception = exception - self.exc_info = exc_info - - @property - def output(self) -> str: - """The terminal output as unicode string, as the user would see it. - - .. versionchanged:: 8.2 - No longer a proxy for ``self.stdout``. Now has its own independent stream - that is mixing `` and ``, in the order they were written. - """ - return self.output_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - @property - def stdout(self) -> str: - """The standard output as unicode string.""" - return self.stdout_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - @property - def stderr(self) -> str: - """The standard error as unicode string. - - .. versionchanged:: 8.2 - No longer raise an exception, always returns the `` string. - """ - return self.stderr_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - def __repr__(self) -> str: - exc_str = repr(self.exception) if self.exception else "okay" - return f"<{type(self).__name__} {exc_str}>" - - -class CliRunner: - """The CLI runner provides functionality to invoke a Click command line - script for unittesting purposes in a isolated environment. This only - works in single-threaded systems without any concurrency as it changes the - global interpreter state. - - :param charset: the character set for the input and output data. - :param env: a dictionary with environment variables for overriding. - :param echo_stdin: if this is set to `True`, then reading from `` writes - to ``. This is useful for showing examples in - some circumstances. Note that regular prompts - will automatically echo the input. - :param catch_exceptions: Whether to catch any exceptions other than - ``SystemExit`` when running :meth:`~CliRunner.invoke`. - - .. versionchanged:: 8.2 - Added the ``catch_exceptions`` parameter. - - .. versionchanged:: 8.2 - ``mix_stderr`` parameter has been removed. - """ - - def __init__( - self, - charset: str = "utf-8", - env: cabc.Mapping[str, str | None] | None = None, - echo_stdin: bool = False, - catch_exceptions: bool = True, - ) -> None: - self.charset = charset - self.env: cabc.Mapping[str, str | None] = env or {} - self.echo_stdin = echo_stdin - self.catch_exceptions = catch_exceptions - - def get_default_prog_name(self, cli: Command) -> str: - """Given a command object it will return the default program name - for it. The default is the `name` attribute or ``"root"`` if not - set. - """ - return cli.name or "root" - - def make_env( - self, overrides: cabc.Mapping[str, str | None] | None = None - ) -> cabc.Mapping[str, str | None]: - """Returns the environment overrides for invoking a script.""" - rv = dict(self.env) - if overrides: - rv.update(overrides) - return rv - - @contextlib.contextmanager - def isolation( - self, - input: str | bytes | t.IO[t.Any] | None = None, - env: cabc.Mapping[str, str | None] | None = None, - color: bool = False, - ) -> cabc.Iterator[tuple[io.BytesIO, io.BytesIO, io.BytesIO]]: - """A context manager that sets up the isolation for invoking of a - command line tool. This sets up `` with the given input data - and `os.environ` with the overrides from the given dictionary. - This also rebinds some internals in Click to be mocked (like the - prompt functionality). - - This is automatically done in the :meth:`invoke` method. - - :param input: the input stream to put into `sys.stdin`. - :param env: the environment overrides as dictionary. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionadded:: 8.2 - An additional output stream is returned, which is a mix of - `` and `` streams. - - .. versionchanged:: 8.2 - Always returns the `` stream. - - .. versionchanged:: 8.0 - `` is opened with ``errors="backslashreplace"`` - instead of the default ``"strict"``. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - """ - bytes_input = make_input_stream(input, self.charset) - echo_input = None - - old_stdin = sys.stdin - old_stdout = sys.stdout - old_stderr = sys.stderr - old_forced_width = formatting.FORCED_WIDTH - formatting.FORCED_WIDTH = 80 - - env = self.make_env(env) - - stream_mixer = StreamMixer() - - if self.echo_stdin: - bytes_input = echo_input = t.cast( - t.BinaryIO, EchoingStdin(bytes_input, stream_mixer.stdout) - ) - - sys.stdin = text_input = _NamedTextIOWrapper( - bytes_input, encoding=self.charset, name="", mode="r" - ) - - if self.echo_stdin: - # Force unbuffered reads, otherwise TextIOWrapper reads a - # large chunk which is echoed early. - text_input._CHUNK_SIZE = 1 # type: ignore - - sys.stdout = _NamedTextIOWrapper( - stream_mixer.stdout, encoding=self.charset, name="", mode="w" - ) - - sys.stderr = _NamedTextIOWrapper( - stream_mixer.stderr, - encoding=self.charset, - name="", - mode="w", - errors="backslashreplace", - ) - - @_pause_echo(echo_input) # type: ignore - def visible_input(prompt: str | None = None) -> str: - sys.stdout.write(prompt or "") - try: - val = next(text_input).rstrip("\r\n") - except StopIteration as e: - raise EOFError() from e - sys.stdout.write(f"{val}\n") - sys.stdout.flush() - return val - - @_pause_echo(echo_input) # type: ignore - def hidden_input(prompt: str | None = None) -> str: - sys.stdout.write(f"{prompt or ''}\n") - sys.stdout.flush() - try: - return next(text_input).rstrip("\r\n") - except StopIteration as e: - raise EOFError() from e - - @_pause_echo(echo_input) # type: ignore - def _getchar(echo: bool) -> str: - char = sys.stdin.read(1) - - if echo: - sys.stdout.write(char) - - sys.stdout.flush() - return char - - default_color = color - - def should_strip_ansi( - stream: t.IO[t.Any] | None = None, color: bool | None = None - ) -> bool: - if color is None: - return not default_color - return not color - - old_visible_prompt_func = termui.visible_prompt_func - old_hidden_prompt_func = termui.hidden_prompt_func - old__getchar_func = termui._getchar - old_should_strip_ansi = utils.should_strip_ansi # type: ignore - old__compat_should_strip_ansi = _compat.should_strip_ansi - termui.visible_prompt_func = visible_input - termui.hidden_prompt_func = hidden_input - termui._getchar = _getchar - utils.should_strip_ansi = should_strip_ansi # type: ignore - _compat.should_strip_ansi = should_strip_ansi - - old_env = {} - try: - for key, value in env.items(): - old_env[key] = os.environ.get(key) - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - yield (stream_mixer.stdout, stream_mixer.stderr, stream_mixer.output) - finally: - for key, value in old_env.items(): - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - sys.stdout = old_stdout - sys.stderr = old_stderr - sys.stdin = old_stdin - termui.visible_prompt_func = old_visible_prompt_func - termui.hidden_prompt_func = old_hidden_prompt_func - termui._getchar = old__getchar_func - utils.should_strip_ansi = old_should_strip_ansi # type: ignore - _compat.should_strip_ansi = old__compat_should_strip_ansi - formatting.FORCED_WIDTH = old_forced_width - - def invoke( - self, - cli: Command, - args: str | cabc.Sequence[str] | None = None, - input: str | bytes | t.IO[t.Any] | None = None, - env: cabc.Mapping[str, str | None] | None = None, - catch_exceptions: bool | None = None, - color: bool = False, - **extra: t.Any, - ) -> Result: - """Invokes a command in an isolated environment. The arguments are - forwarded directly to the command line script, the `extra` keyword - arguments are passed to the :meth:`~clickpkg.Command.main` function of - the command. - - This returns a :class:`Result` object. - - :param cli: the command to invoke - :param args: the arguments to invoke. It may be given as an iterable - or a string. When given as string it will be interpreted - as a Unix shell command. More details at - :func:`shlex.split`. - :param input: the input data for `sys.stdin`. - :param env: the environment overrides. - :param catch_exceptions: Whether to catch any other exceptions than - ``SystemExit``. If :data:`None`, the value - from :class:`CliRunner` is used. - :param extra: the keyword arguments to pass to :meth:`main`. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionadded:: 8.2 - The result object has the ``output_bytes`` attribute with - the mix of ``stdout_bytes`` and ``stderr_bytes``, as the user would - see it in its terminal. - - .. versionchanged:: 8.2 - The result object always returns the ``stderr_bytes`` stream. - - .. versionchanged:: 8.0 - The result object has the ``return_value`` attribute with - the value returned from the invoked command. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionchanged:: 3.0 - Added the ``catch_exceptions`` parameter. - - .. versionchanged:: 3.0 - The result object has the ``exc_info`` attribute with the - traceback if available. - """ - exc_info = None - if catch_exceptions is None: - catch_exceptions = self.catch_exceptions - - with self.isolation(input=input, env=env, color=color) as outstreams: - return_value = None - exception: BaseException | None = None - exit_code = 0 - - if isinstance(args, str): - args = shlex.split(args) - - try: - prog_name = extra.pop("prog_name") - except KeyError: - prog_name = self.get_default_prog_name(cli) - - try: - return_value = cli.main(args=args or (), prog_name=prog_name, **extra) - except SystemExit as e: - exc_info = sys.exc_info() - e_code = t.cast("int | t.Any | None", e.code) - - if e_code is None: - e_code = 0 - - if e_code != 0: - exception = e - - if not isinstance(e_code, int): - sys.stdout.write(str(e_code)) - sys.stdout.write("\n") - e_code = 1 - - exit_code = e_code - - except Exception as e: - if not catch_exceptions: - raise - exception = e - exit_code = 1 - exc_info = sys.exc_info() - finally: - sys.stdout.flush() - sys.stderr.flush() - stdout = outstreams[0].getvalue() - stderr = outstreams[1].getvalue() - output = outstreams[2].getvalue() - - return Result( - runner=self, - stdout_bytes=stdout, - stderr_bytes=stderr, - output_bytes=output, - return_value=return_value, - exit_code=exit_code, - exception=exception, - exc_info=exc_info, # type: ignore - ) - - @contextlib.contextmanager - def isolated_filesystem( - self, temp_dir: str | os.PathLike[str] | None = None - ) -> cabc.Iterator[str]: - """A context manager that creates a temporary directory and - changes the current working directory to it. This isolates tests - that affect the contents of the CWD to prevent them from - interfering with each other. - - :param temp_dir: Create the temporary directory under this - directory. If given, the created directory is not removed - when exiting. - - .. versionchanged:: 8.0 - Added the ``temp_dir`` parameter. - """ - cwd = os.getcwd() - dt = tempfile.mkdtemp(dir=temp_dir) - os.chdir(dt) - - try: - yield dt - finally: - os.chdir(cwd) - - if temp_dir is None: - import shutil - - try: - shutil.rmtree(dt) - except OSError: - pass diff --git a/venv/lib/python3.10/site-packages/click/types.py b/venv/lib/python3.10/site-packages/click/types.py deleted file mode 100644 index e71c1c21e4c2e1f954ceeed228507478f138993a..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/types.py +++ /dev/null @@ -1,1209 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import enum -import os -import stat -import sys -import typing as t -from datetime import datetime -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import _get_argv_encoding -from ._compat import open_stream -from .exceptions import BadParameter -from .utils import format_filename -from .utils import LazyFile -from .utils import safecall - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Context - from .core import Parameter - from .shell_completion import CompletionItem - -ParamTypeValue = t.TypeVar("ParamTypeValue") - - -class ParamType: - """Represents the type of a parameter. Validates and converts values - from the command line or Python into the correct type. - - To implement a custom type, subclass and implement at least the - following: - - - The :attr:`name` class attribute must be set. - - Calling an instance of the type with ``None`` must return - ``None``. This is already implemented by default. - - :meth:`convert` must convert string values to the correct type. - - :meth:`convert` must accept values that are already the correct - type. - - It must be able to convert a value if the ``ctx`` and ``param`` - arguments are ``None``. This can occur when converting prompt - input. - """ - - is_composite: t.ClassVar[bool] = False - arity: t.ClassVar[int] = 1 - - #: the descriptive name of this type - name: str - - #: if a list of this type is expected and the value is pulled from a - #: string environment variable, this is what splits it up. `None` - #: means any whitespace. For all parameters the general rule is that - #: whitespace splits them up. The exception are paths and files which - #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on - #: Windows). - envvar_list_splitter: t.ClassVar[str | None] = None - - def to_info_dict(self) -> dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionadded:: 8.0 - """ - # The class name without the "ParamType" suffix. - param_type = type(self).__name__.partition("ParamType")[0] - param_type = param_type.partition("ParameterType")[0] - - # Custom subclasses might not remember to set a name. - if hasattr(self, "name"): - name = self.name - else: - name = param_type - - return {"param_type": param_type, "name": name} - - def __call__( - self, - value: t.Any, - param: Parameter | None = None, - ctx: Context | None = None, - ) -> t.Any: - if value is not None: - return self.convert(value, param, ctx) - - def get_metavar(self, param: Parameter, ctx: Context) -> str | None: - """Returns the metavar default for this param if it provides one.""" - - def get_missing_message(self, param: Parameter, ctx: Context | None) -> str | None: - """Optionally might return extra information about a missing - parameter. - - .. versionadded:: 2.0 - """ - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - """Convert the value to the correct type. This is not called if - the value is ``None`` (the missing value). - - This must accept string values from the command line, as well as - values that are already the correct type. It may also convert - other compatible types. - - The ``param`` and ``ctx`` arguments may be ``None`` in certain - situations, such as when converting prompt input. - - If the value cannot be converted, call :meth:`fail` with a - descriptive message. - - :param value: The value to convert. - :param param: The parameter that is using this type to convert - its value. May be ``None``. - :param ctx: The current context that arrived at this value. May - be ``None``. - """ - return value - - def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: - """Given a value from an environment variable this splits it up - into small chunks depending on the defined envvar list splitter. - - If the splitter is set to `None`, which means that whitespace splits, - then leading and trailing whitespace is ignored. Otherwise, leading - and trailing splitters usually lead to empty items being included. - """ - return (rv or "").split(self.envvar_list_splitter) - - def fail( - self, - message: str, - param: Parameter | None = None, - ctx: Context | None = None, - ) -> t.NoReturn: - """Helper method to fail with an invalid value message.""" - raise BadParameter(message, ctx=ctx, param=param) - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Return a list of - :class:`~click.shell_completion.CompletionItem` objects for the - incomplete value. Most types do not provide completions, but - some do, and this allows custom types to provide custom - completions as well. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - return [] - - -class CompositeParamType(ParamType): - is_composite = True - - @property - def arity(self) -> int: # type: ignore - raise NotImplementedError() - - -class FuncParamType(ParamType): - def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: - self.name: str = func.__name__ - self.func = func - - def to_info_dict(self) -> dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["func"] = self.func - return info_dict - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - try: - return self.func(value) - except ValueError: - try: - value = str(value) - except UnicodeError: - value = value.decode("utf-8", "replace") - - self.fail(value, param, ctx) - - -class UnprocessedParamType(ParamType): - name = "text" - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - return value - - def __repr__(self) -> str: - return "UNPROCESSED" - - -class StringParamType(ParamType): - name = "text" - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - if isinstance(value, bytes): - enc = _get_argv_encoding() - try: - value = value.decode(enc) - except UnicodeError: - fs_enc = sys.getfilesystemencoding() - if fs_enc != enc: - try: - value = value.decode(fs_enc) - except UnicodeError: - value = value.decode("utf-8", "replace") - else: - value = value.decode("utf-8", "replace") - return value - return str(value) - - def __repr__(self) -> str: - return "STRING" - - -class Choice(ParamType, t.Generic[ParamTypeValue]): - """The choice type allows a value to be checked against a fixed set - of supported values. - - You may pass any iterable value which will be converted to a tuple - and thus will only be iterated once. - - The resulting value will always be one of the originally passed choices. - See :meth:`normalize_choice` for more info on the mapping of strings - to choices. See :ref:`choice-opts` for an example. - - :param case_sensitive: Set to false to make choices case - insensitive. Defaults to true. - - .. versionchanged:: 8.2.0 - Non-``str`` ``choices`` are now supported. It can additionally be any - iterable. Before you were not recommended to pass anything but a list or - tuple. - - .. versionadded:: 8.2.0 - Choice normalization can be overridden via :meth:`normalize_choice`. - """ - - name = "choice" - - def __init__( - self, choices: cabc.Iterable[ParamTypeValue], case_sensitive: bool = True - ) -> None: - self.choices: cabc.Sequence[ParamTypeValue] = tuple(choices) - self.case_sensitive = case_sensitive - - def to_info_dict(self) -> dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["choices"] = self.choices - info_dict["case_sensitive"] = self.case_sensitive - return info_dict - - def _normalized_mapping( - self, ctx: Context | None = None - ) -> cabc.Mapping[ParamTypeValue, str]: - """ - Returns mapping where keys are the original choices and the values are - the normalized values that are accepted via the command line. - - This is a simple wrapper around :meth:`normalize_choice`, use that - instead which is supported. - """ - return { - choice: self.normalize_choice( - choice=choice, - ctx=ctx, - ) - for choice in self.choices - } - - def normalize_choice(self, choice: ParamTypeValue, ctx: Context | None) -> str: - """ - Normalize a choice value, used to map a passed string to a choice. - Each choice must have a unique normalized value. - - By default uses :meth:`Context.token_normalize_func` and if not case - sensitive, convert it to a casefolded value. - - .. versionadded:: 8.2.0 - """ - normed_value = choice.name if isinstance(choice, enum.Enum) else str(choice) - - if ctx is not None and ctx.token_normalize_func is not None: - normed_value = ctx.token_normalize_func(normed_value) - - if not self.case_sensitive: - normed_value = normed_value.casefold() - - return normed_value - - def get_metavar(self, param: Parameter, ctx: Context) -> str | None: - if param.param_type_name == "option" and not param.show_choices: # type: ignore - choice_metavars = [ - convert_type(type(choice)).name.upper() for choice in self.choices - ] - choices_str = "|".join([*dict.fromkeys(choice_metavars)]) - else: - choices_str = "|".join( - [str(i) for i in self._normalized_mapping(ctx=ctx).values()] - ) - - # Use curly braces to indicate a required argument. - if param.required and param.param_type_name == "argument": - return f"{{{choices_str}}}" - - # Use square braces to indicate an option or optional argument. - return f"[{choices_str}]" - - def get_missing_message(self, param: Parameter, ctx: Context | None) -> str: - """ - Message shown when no choice is passed. - - .. versionchanged:: 8.2.0 Added ``ctx`` argument. - """ - return _("Choose from:\n\t{choices}").format( - choices=",\n\t".join(self._normalized_mapping(ctx=ctx).values()) - ) - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> ParamTypeValue: - """ - For a given value from the parser, normalize it and find its - matching normalized value in the list of choices. Then return the - matched "original" choice. - """ - normed_value = self.normalize_choice(choice=value, ctx=ctx) - normalized_mapping = self._normalized_mapping(ctx=ctx) - - try: - return next( - original - for original, normalized in normalized_mapping.items() - if normalized == normed_value - ) - except StopIteration: - self.fail( - self.get_invalid_choice_message(value=value, ctx=ctx), - param=param, - ctx=ctx, - ) - - def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: - """Get the error message when the given choice is invalid. - - :param value: The invalid value. - - .. versionadded:: 8.2 - """ - choices_str = ", ".join(map(repr, self._normalized_mapping(ctx=ctx).values())) - return ngettext( - "{value!r} is not {choice}.", - "{value!r} is not one of {choices}.", - len(self.choices), - ).format(value=value, choice=choices_str, choices=choices_str) - - def __repr__(self) -> str: - return f"Choice({list(self.choices)})" - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Complete choices that start with the incomplete value. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - str_choices = map(str, self.choices) - - if self.case_sensitive: - matched = (c for c in str_choices if c.startswith(incomplete)) - else: - incomplete = incomplete.lower() - matched = (c for c in str_choices if c.lower().startswith(incomplete)) - - return [CompletionItem(c) for c in matched] - - -class DateTime(ParamType): - """The DateTime type converts date strings into `datetime` objects. - - The format strings which are checked are configurable, but default to some - common (non-timezone aware) ISO 8601 formats. - - When specifying *DateTime* formats, you should only pass a list or a tuple. - Other iterables, like generators, may lead to surprising results. - - The format strings are processed using ``datetime.strptime``, and this - consequently defines the format strings which are allowed. - - Parsing is tried using each format, in order, and the first format which - parses successfully is used. - - :param formats: A list or tuple of date format strings, in the order in - which they should be tried. Defaults to - ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, - ``'%Y-%m-%d %H:%M:%S'``. - """ - - name = "datetime" - - def __init__(self, formats: cabc.Sequence[str] | None = None): - self.formats: cabc.Sequence[str] = formats or [ - "%Y-%m-%d", - "%Y-%m-%dT%H:%M:%S", - "%Y-%m-%d %H:%M:%S", - ] - - def to_info_dict(self) -> dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["formats"] = self.formats - return info_dict - - def get_metavar(self, param: Parameter, ctx: Context) -> str | None: - return f"[{'|'.join(self.formats)}]" - - def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: - try: - return datetime.strptime(value, format) - except ValueError: - return None - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - if isinstance(value, datetime): - return value - - for format in self.formats: - converted = self._try_to_convert_date(value, format) - - if converted is not None: - return converted - - formats_str = ", ".join(map(repr, self.formats)) - self.fail( - ngettext( - "{value!r} does not match the format {format}.", - "{value!r} does not match the formats {formats}.", - len(self.formats), - ).format(value=value, format=formats_str, formats=formats_str), - param, - ctx, - ) - - def __repr__(self) -> str: - return "DateTime" - - -class _NumberParamTypeBase(ParamType): - _number_class: t.ClassVar[type[t.Any]] - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - try: - return self._number_class(value) - except ValueError: - self.fail( - _("{value!r} is not a valid {number_type}.").format( - value=value, number_type=self.name - ), - param, - ctx, - ) - - -class _NumberRangeBase(_NumberParamTypeBase): - def __init__( - self, - min: float | None = None, - max: float | None = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - self.min = min - self.max = max - self.min_open = min_open - self.max_open = max_open - self.clamp = clamp - - def to_info_dict(self) -> dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - min=self.min, - max=self.max, - min_open=self.min_open, - max_open=self.max_open, - clamp=self.clamp, - ) - return info_dict - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - import operator - - rv = super().convert(value, param, ctx) - lt_min: bool = self.min is not None and ( - operator.le if self.min_open else operator.lt - )(rv, self.min) - gt_max: bool = self.max is not None and ( - operator.ge if self.max_open else operator.gt - )(rv, self.max) - - if self.clamp: - if lt_min: - return self._clamp(self.min, 1, self.min_open) # type: ignore - - if gt_max: - return self._clamp(self.max, -1, self.max_open) # type: ignore - - if lt_min or gt_max: - self.fail( - _("{value} is not in the range {range}.").format( - value=rv, range=self._describe_range() - ), - param, - ctx, - ) - - return rv - - def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: - """Find the valid value to clamp to bound in the given - direction. - - :param bound: The boundary value. - :param dir: 1 or -1 indicating the direction to move. - :param open: If true, the range does not include the bound. - """ - raise NotImplementedError - - def _describe_range(self) -> str: - """Describe the range for use in help text.""" - if self.min is None: - op = "<" if self.max_open else "<=" - return f"x{op}{self.max}" - - if self.max is None: - op = ">" if self.min_open else ">=" - return f"x{op}{self.min}" - - lop = "<" if self.min_open else "<=" - rop = "<" if self.max_open else "<=" - return f"{self.min}{lop}x{rop}{self.max}" - - def __repr__(self) -> str: - clamp = " clamped" if self.clamp else "" - return f"<{type(self).__name__} {self._describe_range()}{clamp}>" - - -class IntParamType(_NumberParamTypeBase): - name = "integer" - _number_class = int - - def __repr__(self) -> str: - return "INT" - - -class IntRange(_NumberRangeBase, IntParamType): - """Restrict an :data:`click.INT` value to a range of accepted - values. See :ref:`ranges`. - - If ``min`` or ``max`` are not passed, any value is accepted in that - direction. If ``min_open`` or ``max_open`` are enabled, the - corresponding boundary is not included in the range. - - If ``clamp`` is enabled, a value outside the range is clamped to the - boundary instead of failing. - - .. versionchanged:: 8.0 - Added the ``min_open`` and ``max_open`` parameters. - """ - - name = "integer range" - - def _clamp( # type: ignore - self, bound: int, dir: t.Literal[1, -1], open: bool - ) -> int: - if not open: - return bound - - return bound + dir - - -class FloatParamType(_NumberParamTypeBase): - name = "float" - _number_class = float - - def __repr__(self) -> str: - return "FLOAT" - - -class FloatRange(_NumberRangeBase, FloatParamType): - """Restrict a :data:`click.FLOAT` value to a range of accepted - values. See :ref:`ranges`. - - If ``min`` or ``max`` are not passed, any value is accepted in that - direction. If ``min_open`` or ``max_open`` are enabled, the - corresponding boundary is not included in the range. - - If ``clamp`` is enabled, a value outside the range is clamped to the - boundary instead of failing. This is not supported if either - boundary is marked ``open``. - - .. versionchanged:: 8.0 - Added the ``min_open`` and ``max_open`` parameters. - """ - - name = "float range" - - def __init__( - self, - min: float | None = None, - max: float | None = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - super().__init__( - min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp - ) - - if (min_open or max_open) and clamp: - raise TypeError("Clamping is not supported for open bounds.") - - def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: - if not open: - return bound - - # Could use math.nextafter here, but clamping an - # open float range doesn't seem to be particularly useful. It's - # left up to the user to write a callback to do it if needed. - raise RuntimeError("Clamping is not supported for open bounds.") - - -class BoolParamType(ParamType): - name = "boolean" - - bool_states: dict[str, bool] = { - "1": True, - "0": False, - "yes": True, - "no": False, - "true": True, - "false": False, - "on": True, - "off": False, - "t": True, - "f": False, - "y": True, - "n": False, - # Absence of value is considered False. - "": False, - } - """A mapping of string values to boolean states. - - Mapping is inspired by :py:attr:`configparser.ConfigParser.BOOLEAN_STATES` - and extends it. - - .. caution:: - String values are lower-cased, as the ``str_to_bool`` comparison function - below is case-insensitive. - - .. warning:: - The mapping is not exhaustive, and does not cover all possible boolean strings - representations. It will remains as it is to avoid endless bikeshedding. - - Future work my be considered to make this mapping user-configurable from public - API. - """ - - @staticmethod - def str_to_bool(value: str | bool) -> bool | None: - """Convert a string to a boolean value. - - If the value is already a boolean, it is returned as-is. If the value is a - string, it is stripped of whitespaces and lower-cased, then checked against - the known boolean states pre-defined in the `BoolParamType.bool_states` mapping - above. - - Returns `None` if the value does not match any known boolean state. - """ - if isinstance(value, bool): - return value - return BoolParamType.bool_states.get(value.strip().lower()) - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> bool: - normalized = self.str_to_bool(value) - if normalized is None: - self.fail( - _( - "{value!r} is not a valid boolean. Recognized values: {states}" - ).format(value=value, states=", ".join(sorted(self.bool_states))), - param, - ctx, - ) - return normalized - - def __repr__(self) -> str: - return "BOOL" - - -class UUIDParameterType(ParamType): - name = "uuid" - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - import uuid - - if isinstance(value, uuid.UUID): - return value - - value = value.strip() - - try: - return uuid.UUID(value) - except ValueError: - self.fail( - _("{value!r} is not a valid UUID.").format(value=value), param, ctx - ) - - def __repr__(self) -> str: - return "UUID" - - -class File(ParamType): - """Declares a parameter to be a file for reading or writing. The file - is automatically closed once the context tears down (after the command - finished working). - - Files can be opened for reading or writing. The special value ``-`` - indicates stdin or stdout depending on the mode. - - By default, the file is opened for reading text data, but it can also be - opened in binary mode or for writing. The encoding parameter can be used - to force a specific encoding. - - The `lazy` flag controls if the file should be opened immediately or upon - first IO. The default is to be non-lazy for standard input and output - streams as well as files opened for reading, `lazy` otherwise. When opening a - file lazily for reading, it is still opened temporarily for validation, but - will not be held open until first IO. lazy is mainly useful when opening - for writing to avoid creating the file until it is needed. - - Files can also be opened atomically in which case all writes go into a - separate file in the same folder and upon completion the file will - be moved over to the original location. This is useful if a file - regularly read by other users is modified. - - See :ref:`file-args` for more information. - - .. versionchanged:: 2.0 - Added the ``atomic`` parameter. - """ - - name = "filename" - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - lazy: bool | None = None, - atomic: bool = False, - ) -> None: - self.mode = mode - self.encoding = encoding - self.errors = errors - self.lazy = lazy - self.atomic = atomic - - def to_info_dict(self) -> dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update(mode=self.mode, encoding=self.encoding) - return info_dict - - def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: - if self.lazy is not None: - return self.lazy - if os.fspath(value) == "-": - return False - elif "w" in self.mode: - return True - return False - - def convert( - self, - value: str | os.PathLike[str] | t.IO[t.Any], - param: Parameter | None, - ctx: Context | None, - ) -> t.IO[t.Any]: - if _is_file_like(value): - return value - - value = t.cast("str | os.PathLike[str]", value) - - try: - lazy = self.resolve_lazy_flag(value) - - if lazy: - lf = LazyFile( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - if ctx is not None: - ctx.call_on_close(lf.close_intelligently) - - return t.cast("t.IO[t.Any]", lf) - - f, should_close = open_stream( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - # If a context is provided, we automatically close the file - # at the end of the context execution (or flush out). If a - # context does not exist, it's the caller's responsibility to - # properly close the file. This for instance happens when the - # type is used with prompts. - if ctx is not None: - if should_close: - ctx.call_on_close(safecall(f.close)) - else: - ctx.call_on_close(safecall(f.flush)) - - return f - except OSError as e: - self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Return a special completion marker that tells the completion - system to use the shell to provide file path completions. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - return [CompletionItem(incomplete, type="file")] - - -def _is_file_like(value: t.Any) -> te.TypeGuard[t.IO[t.Any]]: - return hasattr(value, "read") or hasattr(value, "write") - - -class Path(ParamType): - """The ``Path`` type is similar to the :class:`File` type, but - returns the filename instead of an open file. Various checks can be - enabled to validate the type of file and permissions. - - :param exists: The file or directory needs to exist for the value to - be valid. If this is not set to ``True``, and the file does not - exist, then all further checks are silently skipped. - :param file_okay: Allow a file as a value. - :param dir_okay: Allow a directory as a value. - :param readable: if true, a readable check is performed. - :param writable: if true, a writable check is performed. - :param executable: if true, an executable check is performed. - :param resolve_path: Make the value absolute and resolve any - symlinks. A ``~`` is not expanded, as this is supposed to be - done by the shell only. - :param allow_dash: Allow a single dash as a value, which indicates - a standard stream (but does not open it). Use - :func:`~click.open_file` to handle opening this value. - :param path_type: Convert the incoming path value to this type. If - ``None``, keep Python's default, which is ``str``. Useful to - convert to :class:`pathlib.Path`. - - .. versionchanged:: 8.1 - Added the ``executable`` parameter. - - .. versionchanged:: 8.0 - Allow passing ``path_type=pathlib.Path``. - - .. versionchanged:: 6.0 - Added the ``allow_dash`` parameter. - """ - - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - exists: bool = False, - file_okay: bool = True, - dir_okay: bool = True, - writable: bool = False, - readable: bool = True, - resolve_path: bool = False, - allow_dash: bool = False, - path_type: type[t.Any] | None = None, - executable: bool = False, - ): - self.exists = exists - self.file_okay = file_okay - self.dir_okay = dir_okay - self.readable = readable - self.writable = writable - self.executable = executable - self.resolve_path = resolve_path - self.allow_dash = allow_dash - self.type = path_type - - if self.file_okay and not self.dir_okay: - self.name: str = _("file") - elif self.dir_okay and not self.file_okay: - self.name = _("directory") - else: - self.name = _("path") - - def to_info_dict(self) -> dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - exists=self.exists, - file_okay=self.file_okay, - dir_okay=self.dir_okay, - writable=self.writable, - readable=self.readable, - allow_dash=self.allow_dash, - ) - return info_dict - - def coerce_path_result( - self, value: str | os.PathLike[str] - ) -> str | bytes | os.PathLike[str]: - if self.type is not None and not isinstance(value, self.type): - if self.type is str: - return os.fsdecode(value) - elif self.type is bytes: - return os.fsencode(value) - else: - return t.cast("os.PathLike[str]", self.type(value)) - - return value - - def convert( - self, - value: str | os.PathLike[str], - param: Parameter | None, - ctx: Context | None, - ) -> str | bytes | os.PathLike[str]: - rv = value - - is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") - - if not is_dash: - if self.resolve_path: - rv = os.path.realpath(rv) - - try: - st = os.stat(rv) - except OSError: - if not self.exists: - return self.coerce_path_result(rv) - self.fail( - _("{name} {filename!r} does not exist.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if not self.file_okay and stat.S_ISREG(st.st_mode): - self.fail( - _("{name} {filename!r} is a file.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - if not self.dir_okay and stat.S_ISDIR(st.st_mode): - self.fail( - _("{name} {filename!r} is a directory.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.readable and not os.access(rv, os.R_OK): - self.fail( - _("{name} {filename!r} is not readable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.writable and not os.access(rv, os.W_OK): - self.fail( - _("{name} {filename!r} is not writable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.executable and not os.access(value, os.X_OK): - self.fail( - _("{name} {filename!r} is not executable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - return self.coerce_path_result(rv) - - def shell_complete( - self, ctx: Context, param: Parameter, incomplete: str - ) -> list[CompletionItem]: - """Return a special completion marker that tells the completion - system to use the shell to provide path completions for only - directories or any paths. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - type = "dir" if self.dir_okay and not self.file_okay else "file" - return [CompletionItem(incomplete, type=type)] - - -class Tuple(CompositeParamType): - """The default behavior of Click is to apply a type on a value directly. - This works well in most cases, except for when `nargs` is set to a fixed - count and different types should be used for different items. In this - case the :class:`Tuple` type can be used. This type can only be used - if `nargs` is set to a fixed number. - - For more information see :ref:`tuple-type`. - - This can be selected by using a Python tuple literal as a type. - - :param types: a list of types that should be used for the tuple items. - """ - - def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType]) -> None: - self.types: cabc.Sequence[ParamType] = [convert_type(ty) for ty in types] - - def to_info_dict(self) -> dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["types"] = [t.to_info_dict() for t in self.types] - return info_dict - - @property - def name(self) -> str: # type: ignore - return f"<{' '.join(ty.name for ty in self.types)}>" - - @property - def arity(self) -> int: # type: ignore - return len(self.types) - - def convert( - self, value: t.Any, param: Parameter | None, ctx: Context | None - ) -> t.Any: - len_type = len(self.types) - len_value = len(value) - - if len_value != len_type: - self.fail( - ngettext( - "{len_type} values are required, but {len_value} was given.", - "{len_type} values are required, but {len_value} were given.", - len_value, - ).format(len_type=len_type, len_value=len_value), - param=param, - ctx=ctx, - ) - - return tuple( - ty(x, param, ctx) for ty, x in zip(self.types, value, strict=False) - ) - - -def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType: - """Find the most appropriate :class:`ParamType` for the given Python - type. If the type isn't provided, it can be inferred from a default - value. - """ - guessed_type = False - - if ty is None and default is not None: - if isinstance(default, (tuple, list)): - # If the default is empty, ty will remain None and will - # return STRING. - if default: - item = default[0] - - # A tuple of tuples needs to detect the inner types. - # Can't call convert recursively because that would - # incorrectly unwind the tuple to a single type. - if isinstance(item, (tuple, list)): - ty = tuple(map(type, item)) - else: - ty = type(item) - else: - ty = type(default) - - guessed_type = True - - if isinstance(ty, tuple): - return Tuple(ty) - - if isinstance(ty, ParamType): - return ty - - if ty is str or ty is None: - return STRING - - if ty is int: - return INT - - if ty is float: - return FLOAT - - if ty is bool: - return BOOL - - if guessed_type: - return STRING - - if __debug__: - try: - if issubclass(ty, ParamType): - raise AssertionError( - f"Attempted to use an uninstantiated parameter type ({ty})." - ) - except TypeError: - # ty is an instance (correct), so issubclass fails. - pass - - return FuncParamType(ty) - - -#: A dummy parameter type that just does nothing. From a user's -#: perspective this appears to just be the same as `STRING` but -#: internally no string conversion takes place if the input was bytes. -#: This is usually useful when working with file paths as they can -#: appear in bytes and unicode. -#: -#: For path related uses the :class:`Path` type is a better choice but -#: there are situations where an unprocessed type is useful which is why -#: it is is provided. -#: -#: .. versionadded:: 4.0 -UNPROCESSED = UnprocessedParamType() - -#: A unicode string parameter type which is the implicit default. This -#: can also be selected by using ``str`` as type. -STRING = StringParamType() - -#: An integer parameter. This can also be selected by using ``int`` as -#: type. -INT = IntParamType() - -#: A floating point value parameter. This can also be selected by using -#: ``float`` as type. -FLOAT = FloatParamType() - -#: A boolean parameter. This is the default for boolean flags. This can -#: also be selected by using ``bool`` as a type. -BOOL = BoolParamType() - -#: A UUID parameter. -UUID = UUIDParameterType() - - -class OptionHelpExtra(t.TypedDict, total=False): - envvars: tuple[str, ...] - default: str - range: str - required: str diff --git a/venv/lib/python3.10/site-packages/click/utils.py b/venv/lib/python3.10/site-packages/click/utils.py deleted file mode 100644 index beae26f761607f0a7a617d4ce8789bf49bb99b6b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/click/utils.py +++ /dev/null @@ -1,627 +0,0 @@ -from __future__ import annotations - -import collections.abc as cabc -import os -import re -import sys -import typing as t -from functools import update_wrapper -from types import ModuleType -from types import TracebackType - -from ._compat import _default_text_stderr -from ._compat import _default_text_stdout -from ._compat import _find_binary_writer -from ._compat import auto_wrap_for_ansi -from ._compat import binary_streams -from ._compat import open_stream -from ._compat import should_strip_ansi -from ._compat import strip_ansi -from ._compat import text_streams -from ._compat import WIN -from .globals import resolve_color_default - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") - - -def _posixify(name: str) -> str: - return "-".join(name.split()).lower() - - -def safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: - """Wraps a function so that it swallows exceptions.""" - - def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: - try: - return func(*args, **kwargs) - except Exception: - pass - return None - - return update_wrapper(wrapper, func) - - -def make_str(value: t.Any) -> str: - """Converts a value into a valid string.""" - if isinstance(value, bytes): - try: - return value.decode(sys.getfilesystemencoding()) - except UnicodeError: - return value.decode("utf-8", "replace") - return str(value) - - -def make_default_short_help(help: str, max_length: int = 45) -> str: - """Returns a condensed version of help string.""" - # Consider only the first paragraph. - paragraph_end = help.find("\n\n") - - if paragraph_end != -1: - help = help[:paragraph_end] - - # Collapse newlines, tabs, and spaces. - words = help.split() - - if not words: - return "" - - # The first paragraph started with a "no rewrap" marker, ignore it. - if words[0] == "\b": - words = words[1:] - - total_length = 0 - last_index = len(words) - 1 - - for i, word in enumerate(words): - total_length += len(word) + (i > 0) - - if total_length > max_length: # too long, truncate - break - - if word[-1] == ".": # sentence end, truncate without "..." - return " ".join(words[: i + 1]) - - if total_length == max_length and i != last_index: - break # not at sentence end, truncate with "..." - else: - return " ".join(words) # no truncation needed - - # Account for the length of the suffix. - total_length += len("...") - - # remove words until the length is short enough - while i > 0: - total_length -= len(words[i]) + (i > 0) - - if total_length <= max_length: - break - - i -= 1 - - return " ".join(words[:i]) + "..." - - -class LazyFile: - """A lazy file works like a regular file but it does not fully open - the file but it does perform some basic checks early to see if the - filename parameter does make sense. This is useful for safely opening - files for writing. - """ - - def __init__( - self, - filename: str | os.PathLike[str], - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - atomic: bool = False, - ): - self.name: str = os.fspath(filename) - self.mode = mode - self.encoding = encoding - self.errors = errors - self.atomic = atomic - self._f: t.IO[t.Any] | None - self.should_close: bool - - if self.name == "-": - self._f, self.should_close = open_stream(filename, mode, encoding, errors) - else: - if "r" in mode: - # Open and close the file in case we're opening it for - # reading so that we can catch at least some errors in - # some cases early. - open(filename, mode).close() - self._f = None - self.should_close = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self.open(), name) - - def __repr__(self) -> str: - if self._f is not None: - return repr(self._f) - return f"" - - def open(self) -> t.IO[t.Any]: - """Opens the file if it's not yet open. This call might fail with - a :exc:`FileError`. Not handling this error will produce an error - that Click shows. - """ - if self._f is not None: - return self._f - try: - rv, self.should_close = open_stream( - self.name, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - except OSError as e: - from .exceptions import FileError - - raise FileError(self.name, hint=e.strerror) from e - self._f = rv - return rv - - def close(self) -> None: - """Closes the underlying file, no matter what.""" - if self._f is not None: - self._f.close() - - def close_intelligently(self) -> None: - """This function only closes the file if it was opened by the lazy - file wrapper. For instance this will never close stdin. - """ - if self.should_close: - self.close() - - def __enter__(self) -> LazyFile: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - self.close_intelligently() - - def __iter__(self) -> cabc.Iterator[t.AnyStr]: - self.open() - return iter(self._f) # type: ignore - - -class KeepOpenFile: - def __init__(self, file: t.IO[t.Any]) -> None: - self._file: t.IO[t.Any] = file - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._file, name) - - def __enter__(self) -> KeepOpenFile: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - tb: TracebackType | None, - ) -> None: - pass - - def __repr__(self) -> str: - return repr(self._file) - - def __iter__(self) -> cabc.Iterator[t.AnyStr]: - return iter(self._file) - - -def echo( - message: t.Any | None = None, - file: t.IO[t.Any] | None = None, - nl: bool = True, - err: bool = False, - color: bool | None = None, -) -> None: - """Print a message and newline to stdout or a file. This should be - used instead of :func:`print` because it provides better support - for different data, files, and environments. - - Compared to :func:`print`, this does the following: - - - Ensures that the output encoding is not misconfigured on Linux. - - Supports Unicode in the Windows console. - - Supports writing to binary outputs, and supports writing bytes - to text outputs. - - Supports colors and styles on Windows. - - Removes ANSI color and style codes if the output does not look - like an interactive terminal. - - Always flushes the output. - - :param message: The string or bytes to output. Other objects are - converted to strings. - :param file: The file to write to. Defaults to ``stdout``. - :param err: Write to ``stderr`` instead of ``stdout``. - :param nl: Print a newline after the message. Enabled by default. - :param color: Force showing or hiding colors and other styles. By - default Click will remove color if the output does not look like - an interactive terminal. - - .. versionchanged:: 6.0 - Support Unicode output on the Windows console. Click does not - modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` - will still not support Unicode. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionadded:: 3.0 - Added the ``err`` parameter. - - .. versionchanged:: 2.0 - Support colors on Windows if colorama is installed. - """ - if file is None: - if err: - file = _default_text_stderr() - else: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - return - - # Convert non bytes/text into the native string type. - if message is not None and not isinstance(message, (str, bytes, bytearray)): - out: str | bytes | bytearray | None = str(message) - else: - out = message - - if nl: - out = out or "" - if isinstance(out, str): - out += "\n" - else: - out += b"\n" - - if not out: - file.flush() - return - - # If there is a message and the value looks like bytes, we manually - # need to find the binary stream and write the message in there. - # This is done separately so that most stream types will work as you - # would expect. Eg: you can write to StringIO for other cases. - if isinstance(out, (bytes, bytearray)): - binary_file = _find_binary_writer(file) - - if binary_file is not None: - file.flush() - binary_file.write(out) - binary_file.flush() - return - - # ANSI style code support. For no message or bytes, nothing happens. - # When outputting to a file instead of a terminal, strip codes. - else: - color = resolve_color_default(color) - - if should_strip_ansi(file, color): - out = strip_ansi(out) - elif WIN: - if auto_wrap_for_ansi is not None: - file = auto_wrap_for_ansi(file, color) # type: ignore - elif not color: - out = strip_ansi(out) - - file.write(out) # type: ignore - file.flush() - - -def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: - """Returns a system stream for byte processing. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - """ - opener = binary_streams.get(name) - if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") - return opener() - - -def get_text_stream( - name: t.Literal["stdin", "stdout", "stderr"], - encoding: str | None = None, - errors: str | None = "strict", -) -> t.TextIO: - """Returns a system stream for text processing. This usually returns - a wrapped stream around a binary stream returned from - :func:`get_binary_stream` but it also can take shortcuts for already - correctly configured streams. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - :param encoding: overrides the detected default encoding. - :param errors: overrides the default error mode. - """ - opener = text_streams.get(name) - if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") - return opener(encoding, errors) - - -def open_file( - filename: str | os.PathLike[str], - mode: str = "r", - encoding: str | None = None, - errors: str | None = "strict", - lazy: bool = False, - atomic: bool = False, -) -> t.IO[t.Any]: - """Open a file, with extra behavior to handle ``'-'`` to indicate - a standard stream, lazy open on write, and atomic write. Similar to - the behavior of the :class:`~click.File` param type. - - If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is - wrapped so that using it in a context manager will not close it. - This makes it possible to use the function without accidentally - closing a standard stream: - - .. code-block:: python - - with open_file(filename) as f: - ... - - :param filename: The name or Path of the file to open, or ``'-'`` for - ``stdin``/``stdout``. - :param mode: The mode in which to open the file. - :param encoding: The encoding to decode or encode a file opened in - text mode. - :param errors: The error handling mode. - :param lazy: Wait to open the file until it is accessed. For read - mode, the file is temporarily opened to raise access errors - early, then closed until it is read again. - :param atomic: Write to a temporary file and replace the given file - on close. - - .. versionadded:: 3.0 - """ - if lazy: - return t.cast( - "t.IO[t.Any]", LazyFile(filename, mode, encoding, errors, atomic=atomic) - ) - - f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) - - if not should_close: - f = t.cast("t.IO[t.Any]", KeepOpenFile(f)) - - return f - - -def format_filename( - filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], - shorten: bool = False, -) -> str: - """Format a filename as a string for display. Ensures the filename can be - displayed by replacing any invalid bytes or surrogate escapes in the name - with the replacement character ``�``. - - Invalid bytes or surrogate escapes will raise an error when written to a - stream with ``errors="strict"``. This will typically happen with ``stdout`` - when the locale is something like ``en_GB.UTF-8``. - - Many scenarios *are* safe to write surrogates though, due to PEP 538 and - PEP 540, including: - - - Writing to ``stderr``, which uses ``errors="backslashreplace"``. - - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens - stdout and stderr with ``errors="surrogateescape"``. - - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. - - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. - Python opens stdout and stderr with ``errors="surrogateescape"``. - - :param filename: formats a filename for UI display. This will also convert - the filename into unicode without failing. - :param shorten: this optionally shortens the filename to strip of the - path that leads up to it. - """ - if shorten: - filename = os.path.basename(filename) - else: - filename = os.fspath(filename) - - if isinstance(filename, bytes): - filename = filename.decode(sys.getfilesystemencoding(), "replace") - else: - filename = filename.encode("utf-8", "surrogateescape").decode( - "utf-8", "replace" - ) - - return filename - - -def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: - r"""Returns the config folder for the application. The default behavior - is to return whatever is most appropriate for the operating system. - - To give you an idea, for an app called ``"Foo Bar"``, something like - the following folders could be returned: - - Mac OS X: - ``~/Library/Application Support/Foo Bar`` - Mac OS X (POSIX): - ``~/.foo-bar`` - Unix: - ``~/.config/foo-bar`` - Unix (POSIX): - ``~/.foo-bar`` - Windows (roaming): - ``C:\Users\\AppData\Roaming\Foo Bar`` - Windows (not roaming): - ``C:\Users\\AppData\Local\Foo Bar`` - - .. versionadded:: 2.0 - - :param app_name: the application name. This should be properly capitalized - and can contain whitespace. - :param roaming: controls if the folder should be roaming or not on Windows. - Has no effect otherwise. - :param force_posix: if this is set to `True` then on any POSIX system the - folder will be stored in the home folder with a leading - dot instead of the XDG config home or darwin's - application support folder. - """ - if WIN: - key = "APPDATA" if roaming else "LOCALAPPDATA" - folder = os.environ.get(key) - if folder is None: - folder = os.path.expanduser("~") - return os.path.join(folder, app_name) - if force_posix: - return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) - if sys.platform == "darwin": - return os.path.join( - os.path.expanduser("~/Library/Application Support"), app_name - ) - return os.path.join( - os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), - _posixify(app_name), - ) - - -class PacifyFlushWrapper: - """This wrapper is used to catch and suppress BrokenPipeErrors resulting - from ``.flush()`` being called on broken pipe during the shutdown/final-GC - of the Python interpreter. Notably ``.flush()`` is always called on - ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any - other cleanup code, and the case where the underlying file is not a broken - pipe, all calls and attributes are proxied. - """ - - def __init__(self, wrapped: t.IO[t.Any]) -> None: - self.wrapped = wrapped - - def flush(self) -> None: - try: - self.wrapped.flush() - except OSError as e: - import errno - - if e.errno != errno.EPIPE: - raise - - def __getattr__(self, attr: str) -> t.Any: - return getattr(self.wrapped, attr) - - -def _detect_program_name( - path: str | None = None, _main: ModuleType | None = None -) -> str: - """Determine the command used to run the program, for use in help - text. If a file or entry point was executed, the file name is - returned. If ``python -m`` was used to execute a module or package, - ``python -m name`` is returned. - - This doesn't try to be too precise, the goal is to give a concise - name for help text. Files are only shown as their name without the - path. ``python`` is only shown for modules, and the full path to - ``sys.executable`` is not shown. - - :param path: The Python file being executed. Python puts this in - ``sys.argv[0]``, which is used by default. - :param _main: The ``__main__`` module. This should only be passed - during internal testing. - - .. versionadded:: 8.0 - Based on command args detection in the Werkzeug reloader. - - :meta private: - """ - if _main is None: - _main = sys.modules["__main__"] - - if not path: - path = sys.argv[0] - - # The value of __package__ indicates how Python was called. It may - # not exist if a setuptools script is installed as an egg. It may be - # set incorrectly for entry points created with pip on Windows. - # It is set to "" inside a Shiv or PEX zipapp. - if getattr(_main, "__package__", None) in {None, ""} or ( - os.name == "nt" - and _main.__package__ == "" - and not os.path.exists(path) - and os.path.exists(f"{path}.exe") - ): - # Executed a file, like "python app.py". - return os.path.basename(path) - - # Executed a module, like "python -m example". - # Rewritten by Python from "-m script" to "/path/to/script.py". - # Need to look at main module to determine how it was executed. - py_module = t.cast(str, _main.__package__) - name = os.path.splitext(os.path.basename(path))[0] - - # A submodule like "example.cli". - if name != "__main__": - py_module = f"{py_module}.{name}" - - return f"python -m {py_module.lstrip('.')}" - - -def _expand_args( - args: cabc.Iterable[str], - *, - user: bool = True, - env: bool = True, - glob_recursive: bool = True, -) -> list[str]: - """Simulate Unix shell expansion with Python functions. - - See :func:`glob.glob`, :func:`os.path.expanduser`, and - :func:`os.path.expandvars`. - - This is intended for use on Windows, where the shell does not do any - expansion. It may not exactly match what a Unix shell would do. - - :param args: List of command line arguments to expand. - :param user: Expand user home directory. - :param env: Expand environment variables. - :param glob_recursive: ``**`` matches directories recursively. - - .. versionchanged:: 8.1 - Invalid glob patterns are treated as empty expansions rather - than raising an error. - - .. versionadded:: 8.0 - - :meta private: - """ - from glob import glob - - out = [] - - for arg in args: - if user: - arg = os.path.expanduser(arg) - - if env: - arg = os.path.expandvars(arg) - - try: - matches = glob(arg, recursive=glob_recursive) - except re.error: - matches = [] - - if not matches: - out.append(arg) - else: - out.extend(matches) - - return out diff --git a/venv/lib/python3.10/site-packages/distutils-precedence.pth b/venv/lib/python3.10/site-packages/distutils-precedence.pth deleted file mode 100644 index 10c404f6ad452c148c46a39e11ddd4bc58530d16..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/distutils-precedence.pth +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ea7ffef3fe2a117ee12c68ed6553617f0d7fd2f0590257c25c484959a3b7373 -size 152 diff --git a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/METADATA b/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/METADATA deleted file mode 100644 index e1a9a27f56e8ab864801962bbd8c89b71c1818b4..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/METADATA +++ /dev/null @@ -1,159 +0,0 @@ -Metadata-Version: 2.4 -Name: exceptiongroup -Version: 1.3.1 -Summary: Backport of PEP 654 (exception groups) -Author-email: Alex Grönholm -Requires-Python: >=3.7 -Description-Content-Type: text/x-rst -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Typing :: Typed -License-File: LICENSE -Requires-Dist: typing-extensions >= 4.6.0; python_version < '3.13' -Requires-Dist: pytest >= 6 ; extra == "test" -Project-URL: Changelog, https://github.com/agronholm/exceptiongroup/blob/main/CHANGES.rst -Project-URL: Issue Tracker, https://github.com/agronholm/exceptiongroup/issues -Project-URL: Source code, https://github.com/agronholm/exceptiongroup -Provides-Extra: test - -.. image:: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml/badge.svg - :target: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml - :alt: Build Status -.. image:: https://coveralls.io/repos/github/agronholm/exceptiongroup/badge.svg?branch=main - :target: https://coveralls.io/github/agronholm/exceptiongroup?branch=main - :alt: Code Coverage - -This is a backport of the ``BaseExceptionGroup`` and ``ExceptionGroup`` classes from -Python 3.11. - -It contains the following: - -* The ``exceptiongroup.BaseExceptionGroup`` and ``exceptiongroup.ExceptionGroup`` - classes -* A utility function (``exceptiongroup.catch()``) for catching exceptions possibly - nested in an exception group -* Patches to the ``TracebackException`` class that properly formats exception groups - (installed on import) -* An exception hook that handles formatting of exception groups through - ``TracebackException`` (installed on import) -* Special versions of some of the functions from the ``traceback`` module, modified to - correctly handle exception groups even when monkey patching is disabled, or blocked by - another custom exception hook: - - * ``traceback.format_exception()`` - * ``traceback.format_exception_only()`` - * ``traceback.print_exception()`` - * ``traceback.print_exc()`` -* A backported version of ``contextlib.suppress()`` from Python 3.12.1 which also - handles suppressing exceptions inside exception groups - -If this package is imported on Python 3.11 or later, the built-in implementations of the -exception group classes are used instead, ``TracebackException`` is not monkey patched -and the exception hook won't be installed. - -See the `standard library documentation`_ for more information on exception groups. - -.. _standard library documentation: https://docs.python.org/3/library/exceptions.html - -Catching exceptions -=================== - -Due to the lack of the ``except*`` syntax introduced by `PEP 654`_ in earlier Python -versions, you need to use ``exceptiongroup.catch()`` to catch exceptions that are -potentially nested inside an exception group. This function returns a context manager -that calls the given handler for any exceptions matching the sole argument. - -The argument to ``catch()`` must be a dict (or any ``Mapping``) where each key is either -an exception class or an iterable of exception classes. Each value must be a callable -that takes a single positional argument. The handler will be called at most once, with -an exception group as an argument which will contain all the exceptions that are any -of the given types, or their subclasses. The exception group may contain nested groups -containing more matching exceptions. - -Thus, the following Python 3.11+ code: - -.. code-block:: python - - try: - ... - except* (ValueError, KeyError) as excgroup: - for exc in excgroup.exceptions: - print('Caught exception:', type(exc)) - except* RuntimeError: - print('Caught runtime error') - -would be written with this backport like this: - -.. code-block:: python - - from exceptiongroup import BaseExceptionGroup, catch - - def value_key_err_handler(excgroup: BaseExceptionGroup) -> None: - for exc in excgroup.exceptions: - print('Caught exception:', type(exc)) - - def runtime_err_handler(exc: BaseExceptionGroup) -> None: - print('Caught runtime error') - - with catch({ - (ValueError, KeyError): value_key_err_handler, - RuntimeError: runtime_err_handler - }): - ... - -**NOTE**: Just like with ``except*``, you cannot handle ``BaseExceptionGroup`` or -``ExceptionGroup`` with ``catch()``. - -Suppressing exceptions -====================== - -This library contains a backport of the ``contextlib.suppress()`` context manager from -Python 3.12.1. It allows you to selectively ignore certain exceptions, even when they're -inside exception groups: - -.. code-block:: python - - from exceptiongroup import suppress - - with suppress(RuntimeError): - raise ExceptionGroup("", [RuntimeError("boo")]) - -Notes on monkey patching -======================== - -To make exception groups render properly when an unhandled exception group is being -printed out, this package does two things when it is imported on any Python version -earlier than 3.11: - -#. The ``traceback.TracebackException`` class is monkey patched to store extra - information about exception groups (in ``__init__()``) and properly format them (in - ``format()``) -#. An exception hook is installed at ``sys.excepthook``, provided that no other hook is - already present. This hook causes the exception to be formatted using - ``traceback.TracebackException`` rather than the built-in rendered. - -If ``sys.exceptionhook`` is found to be set to something else than the default when -``exceptiongroup`` is imported, no monkeypatching is done at all. - -To prevent the exception hook and patches from being installed, set the environment -variable ``EXCEPTIONGROUP_NO_PATCH`` to ``1``. - -Formatting exception groups ---------------------------- - -Normally, the monkey patching applied by this library on import will cause exception -groups to be printed properly in tracebacks. But in cases when the monkey patching is -blocked by a third party exception hook, or monkey patching is explicitly disabled, -you can still manually format exceptions using the special versions of the ``traceback`` -functions, like ``format_exception()``, listed at the top of this page. They work just -like their counterparts in the ``traceback`` module, except that they use a separately -patched subclass of ``TracebackException`` to perform the rendering. - -Particularly in cases where a library installs its own exception hook, it is recommended -to use these special versions to do the actual formatting of exceptions/tracebacks. - -.. _PEP 654: https://www.python.org/dev/peps/pep-0654/ - diff --git a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/RECORD b/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/RECORD deleted file mode 100644 index 10fd78352ebea856d3da2c6a38c1c0873026f24c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/RECORD +++ /dev/null @@ -1,18 +0,0 @@ -exceptiongroup-1.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -exceptiongroup-1.3.1.dist-info/METADATA,sha256=gZhKUjovelIq0SvqeEqLuF7ewIBeu9D7TjUBaaNt2AI,6725 -exceptiongroup-1.3.1.dist-info/RECORD,, -exceptiongroup-1.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -exceptiongroup-1.3.1.dist-info/licenses/LICENSE,sha256=blBw12UDHgrUA6HL-Qrm0ZoCKPgC4yC3rP9GCqcu1Hw,3704 -exceptiongroup/__init__.py,sha256=7DHS0hDk-RIs3IQc3SbZVB0-1MhiSCJ9XgvEyEloL7M,1049 -exceptiongroup/__pycache__/__init__.cpython-310.pyc,, -exceptiongroup/__pycache__/_catch.cpython-310.pyc,, -exceptiongroup/__pycache__/_exceptions.cpython-310.pyc,, -exceptiongroup/__pycache__/_formatting.cpython-310.pyc,, -exceptiongroup/__pycache__/_suppress.cpython-310.pyc,, -exceptiongroup/__pycache__/_version.cpython-310.pyc,, -exceptiongroup/_catch.py,sha256=CaJez3E-Jkr-7B7RT3fzusdLWnuyeekooSFn7KyWt9s,4680 -exceptiongroup/_exceptions.py,sha256=wPwPsZ64SXEptuwb4XrTIa1Mc78uqF5vmCrXTdllLn4,11463 -exceptiongroup/_formatting.py,sha256=OYTuT_T6TzM8G2v3DVt8LRBwMNyNK0tNl0fKMls3chM,21063 -exceptiongroup/_suppress.py,sha256=LX11PRNpchwfNWwEMY92nYN1F_5qFenQcS8EjIONXKE,1772 -exceptiongroup/_version.py,sha256=-4u7pjQ4caDQqa-1Qgms81j5hpkXjmjUYRCVEaLmb88,704 -exceptiongroup/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/WHEEL b/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/WHEEL deleted file mode 100644 index d8b9936dad9ab2513fa6979f411560d3b6b57e37..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/licenses/LICENSE deleted file mode 100644 index 50d4fa5e68439ce837f6eef437b299c0dd7c8594..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup-1.3.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,73 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2022 Alex Grönholm - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This project contains code copied from the Python standard library. -The following is the required license notice for those parts. - -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 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/__init__.py b/venv/lib/python3.10/site-packages/exceptiongroup/__init__.py deleted file mode 100644 index d8e36b2e65d11e7f3b2c540c1b292a39a6cc219d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -__all__ = [ - "BaseExceptionGroup", - "ExceptionGroup", - "catch", - "format_exception", - "format_exception_only", - "print_exception", - "print_exc", - "suppress", -] - -import os -import sys - -from ._catch import catch -from ._version import version as __version__ # noqa: F401 - -if sys.version_info < (3, 11): - from ._exceptions import BaseExceptionGroup, ExceptionGroup - from ._formatting import ( - format_exception, - format_exception_only, - print_exc, - print_exception, - ) - - if os.getenv("EXCEPTIONGROUP_NO_PATCH") != "1": - from . import _formatting # noqa: F401 - - BaseExceptionGroup.__module__ = __name__ - ExceptionGroup.__module__ = __name__ -else: - from traceback import ( - format_exception, - format_exception_only, - print_exc, - print_exception, - ) - - BaseExceptionGroup = BaseExceptionGroup - ExceptionGroup = ExceptionGroup - -if sys.version_info < (3, 12, 1): - from ._suppress import suppress -else: - from contextlib import suppress diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index f81ed1a2b590b1103339ef5f7b642faca7d043c4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_catch.cpython-310.pyc b/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_catch.cpython-310.pyc deleted file mode 100644 index dcf0f99cb69ef60886d49d50a7d468aef620d8df..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_catch.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_exceptions.cpython-310.pyc b/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_exceptions.cpython-310.pyc deleted file mode 100644 index eaa5372d3a948c90cc11c3221d7f2a3db3b11dce..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_exceptions.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_formatting.cpython-310.pyc b/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_formatting.cpython-310.pyc deleted file mode 100644 index e5a0761d7968f8bc636ce2a0dcd64a4a014ce6ce..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_formatting.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_suppress.cpython-310.pyc b/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_suppress.cpython-310.pyc deleted file mode 100644 index b36714785b2ba36259df18109e9464098ce6a46e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_suppress.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_version.cpython-310.pyc b/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_version.cpython-310.pyc deleted file mode 100644 index aa2c7b4fcbfc67d658372cc7127a2876f3e1a577..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_version.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/_catch.py b/venv/lib/python3.10/site-packages/exceptiongroup/_catch.py deleted file mode 100644 index 0246568bd05013ed797e0514181aa43bdc59c63e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup/_catch.py +++ /dev/null @@ -1,138 +0,0 @@ -from __future__ import annotations - -import inspect -import sys -from collections.abc import Callable, Iterable, Mapping -from contextlib import AbstractContextManager -from types import TracebackType -from typing import TYPE_CHECKING, Any - -if sys.version_info < (3, 11): - from ._exceptions import BaseExceptionGroup - -if TYPE_CHECKING: - _Handler = Callable[[BaseExceptionGroup[Any]], Any] - - -class _Catcher: - def __init__(self, handler_map: Mapping[tuple[type[BaseException], ...], _Handler]): - self._handler_map = handler_map - - def __enter__(self) -> None: - pass - - def __exit__( - self, - etype: type[BaseException] | None, - exc: BaseException | None, - tb: TracebackType | None, - ) -> bool: - if exc is not None: - unhandled = self.handle_exception(exc) - if unhandled is exc: - return False - elif unhandled is None: - return True - else: - if isinstance(exc, BaseExceptionGroup): - try: - raise unhandled from exc.__cause__ - except BaseExceptionGroup: - # Change __context__ to __cause__ because Python 3.11 does this - # too - unhandled.__context__ = exc.__cause__ - raise - - raise unhandled from exc - - return False - - def handle_exception(self, exc: BaseException) -> BaseException | None: - excgroup: BaseExceptionGroup | None - if isinstance(exc, BaseExceptionGroup): - excgroup = exc - else: - excgroup = BaseExceptionGroup("", [exc]) - - new_exceptions: list[BaseException] = [] - for exc_types, handler in self._handler_map.items(): - matched, excgroup = excgroup.split(exc_types) - if matched: - try: - try: - raise matched - except BaseExceptionGroup: - result = handler(matched) - except BaseExceptionGroup as new_exc: - if new_exc is matched: - new_exceptions.append(new_exc) - else: - new_exceptions.extend(new_exc.exceptions) - except BaseException as new_exc: - new_exceptions.append(new_exc) - else: - if inspect.iscoroutine(result): - raise TypeError( - f"Error trying to handle {matched!r} with {handler!r}. " - "Exception handler must be a sync function." - ) from exc - - if not excgroup: - break - - if new_exceptions: - if len(new_exceptions) == 1: - return new_exceptions[0] - - return BaseExceptionGroup("", new_exceptions) - elif ( - excgroup and len(excgroup.exceptions) == 1 and excgroup.exceptions[0] is exc - ): - return exc - else: - return excgroup - - -def catch( - __handlers: Mapping[type[BaseException] | Iterable[type[BaseException]], _Handler], -) -> AbstractContextManager[None]: - if not isinstance(__handlers, Mapping): - raise TypeError("the argument must be a mapping") - - handler_map: dict[ - tuple[type[BaseException], ...], Callable[[BaseExceptionGroup]] - ] = {} - for type_or_iterable, handler in __handlers.items(): - iterable: tuple[type[BaseException]] - if isinstance(type_or_iterable, type) and issubclass( - type_or_iterable, BaseException - ): - iterable = (type_or_iterable,) - elif isinstance(type_or_iterable, Iterable): - iterable = tuple(type_or_iterable) - else: - raise TypeError( - "each key must be either an exception classes or an iterable thereof" - ) - - if not callable(handler): - raise TypeError("handlers must be callable") - - for exc_type in iterable: - if not isinstance(exc_type, type) or not issubclass( - exc_type, BaseException - ): - raise TypeError( - "each key must be either an exception classes or an iterable " - "thereof" - ) - - if issubclass(exc_type, BaseExceptionGroup): - raise TypeError( - "catching ExceptionGroup with catch() is not allowed. " - "Use except instead." - ) - - handler_map[iterable] = handler - - return _Catcher(handler_map) diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py b/venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py deleted file mode 100644 index f42c1ad3628d927776f82dbd180cd499f26cd34d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py +++ /dev/null @@ -1,336 +0,0 @@ -from __future__ import annotations - -import sys -from collections.abc import Callable, Sequence -from functools import partial -from inspect import getmro, isclass -from typing import TYPE_CHECKING, Generic, Type, TypeVar, cast, overload - -if sys.version_info < (3, 13): - from typing_extensions import TypeVar - -_BaseExceptionT_co = TypeVar( - "_BaseExceptionT_co", bound=BaseException, covariant=True, default=BaseException -) -_BaseExceptionT = TypeVar("_BaseExceptionT", bound=BaseException) -_ExceptionT_co = TypeVar( - "_ExceptionT_co", bound=Exception, covariant=True, default=Exception -) -_ExceptionT = TypeVar("_ExceptionT", bound=Exception) -# using typing.Self would require a typing_extensions dependency on py<3.11 -_ExceptionGroupSelf = TypeVar("_ExceptionGroupSelf", bound="ExceptionGroup") -_BaseExceptionGroupSelf = TypeVar("_BaseExceptionGroupSelf", bound="BaseExceptionGroup") - - -def check_direct_subclass( - exc: BaseException, parents: tuple[type[BaseException]] -) -> bool: - for cls in getmro(exc.__class__)[:-1]: - if cls in parents: - return True - - return False - - -def get_condition_filter( - condition: type[_BaseExceptionT] - | tuple[type[_BaseExceptionT], ...] - | Callable[[_BaseExceptionT_co], bool], -) -> Callable[[_BaseExceptionT_co], bool]: - if isclass(condition) and issubclass( - cast(Type[BaseException], condition), BaseException - ): - return partial(check_direct_subclass, parents=(condition,)) - elif isinstance(condition, tuple): - if all(isclass(x) and issubclass(x, BaseException) for x in condition): - return partial(check_direct_subclass, parents=condition) - elif callable(condition): - return cast("Callable[[BaseException], bool]", condition) - - raise TypeError("expected a function, exception type or tuple of exception types") - - -def _derive_and_copy_attributes(self, excs): - eg = self.derive(excs) - eg.__cause__ = self.__cause__ - eg.__context__ = self.__context__ - eg.__traceback__ = self.__traceback__ - if hasattr(self, "__notes__"): - # Create a new list so that add_note() only affects one exceptiongroup - eg.__notes__ = list(self.__notes__) - return eg - - -class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]): - """A combination of multiple unrelated exceptions.""" - - def __new__( - cls: type[_BaseExceptionGroupSelf], - __message: str, - __exceptions: Sequence[_BaseExceptionT_co], - ) -> _BaseExceptionGroupSelf: - if not isinstance(__message, str): - raise TypeError(f"argument 1 must be str, not {type(__message)}") - if not isinstance(__exceptions, Sequence): - raise TypeError("second argument (exceptions) must be a sequence") - if not __exceptions: - raise ValueError( - "second argument (exceptions) must be a non-empty sequence" - ) - - for i, exc in enumerate(__exceptions): - if not isinstance(exc, BaseException): - raise ValueError( - f"Item {i} of second argument (exceptions) is not an exception" - ) - - if cls is BaseExceptionGroup: - if all(isinstance(exc, Exception) for exc in __exceptions): - cls = ExceptionGroup - - if issubclass(cls, Exception): - for exc in __exceptions: - if not isinstance(exc, Exception): - if cls is ExceptionGroup: - raise TypeError( - "Cannot nest BaseExceptions in an ExceptionGroup" - ) - else: - raise TypeError( - f"Cannot nest BaseExceptions in {cls.__name__!r}" - ) - - instance = super().__new__(cls, __message, __exceptions) - instance._exceptions = tuple(__exceptions) - return instance - - def __init__( - self, - __message: str, - __exceptions: Sequence[_BaseExceptionT_co], - *args: object, - ) -> None: - BaseException.__init__(self, __message, __exceptions, *args) - - def add_note(self, note: str) -> None: - if not isinstance(note, str): - raise TypeError( - f"Expected a string, got note={note!r} (type {type(note).__name__})" - ) - - if not hasattr(self, "__notes__"): - self.__notes__: list[str] = [] - - self.__notes__.append(note) - - @property - def message(self) -> str: - return self.args[0] - - @property - def exceptions( - self, - ) -> tuple[_BaseExceptionT_co | BaseExceptionGroup[_BaseExceptionT_co], ...]: - return tuple(self._exceptions) - - @overload - def subgroup( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> ExceptionGroup[_ExceptionT] | None: ... - - @overload - def subgroup( - self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] - ) -> BaseExceptionGroup[_BaseExceptionT] | None: ... - - @overload - def subgroup( - self, - __condition: Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool], - ) -> BaseExceptionGroup[_BaseExceptionT_co] | None: ... - - def subgroup( - self, - __condition: type[_BaseExceptionT] - | tuple[type[_BaseExceptionT], ...] - | Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool], - ) -> BaseExceptionGroup[_BaseExceptionT] | None: - condition = get_condition_filter(__condition) - modified = False - if condition(self): - return self - - exceptions: list[BaseException] = [] - for exc in self.exceptions: - if isinstance(exc, BaseExceptionGroup): - subgroup = exc.subgroup(__condition) - if subgroup is not None: - exceptions.append(subgroup) - - if subgroup is not exc: - modified = True - elif condition(exc): - exceptions.append(exc) - else: - modified = True - - if not modified: - return self - elif exceptions: - group = _derive_and_copy_attributes(self, exceptions) - return group - else: - return None - - @overload - def split( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> tuple[ - ExceptionGroup[_ExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ]: ... - - @overload - def split( - self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] - ) -> tuple[ - BaseExceptionGroup[_BaseExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ]: ... - - @overload - def split( - self, - __condition: Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool], - ) -> tuple[ - BaseExceptionGroup[_BaseExceptionT_co] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ]: ... - - def split( - self, - __condition: type[_BaseExceptionT] - | tuple[type[_BaseExceptionT], ...] - | Callable[[_BaseExceptionT_co], bool], - ) -> ( - tuple[ - ExceptionGroup[_ExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ] - | tuple[ - BaseExceptionGroup[_BaseExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ] - | tuple[ - BaseExceptionGroup[_BaseExceptionT_co] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ] - ): - condition = get_condition_filter(__condition) - if condition(self): - return self, None - - matching_exceptions: list[BaseException] = [] - nonmatching_exceptions: list[BaseException] = [] - for exc in self.exceptions: - if isinstance(exc, BaseExceptionGroup): - matching, nonmatching = exc.split(condition) - if matching is not None: - matching_exceptions.append(matching) - - if nonmatching is not None: - nonmatching_exceptions.append(nonmatching) - elif condition(exc): - matching_exceptions.append(exc) - else: - nonmatching_exceptions.append(exc) - - matching_group: _BaseExceptionGroupSelf | None = None - if matching_exceptions: - matching_group = _derive_and_copy_attributes(self, matching_exceptions) - - nonmatching_group: _BaseExceptionGroupSelf | None = None - if nonmatching_exceptions: - nonmatching_group = _derive_and_copy_attributes( - self, nonmatching_exceptions - ) - - return matching_group, nonmatching_group - - @overload - def derive(self, __excs: Sequence[_ExceptionT]) -> ExceptionGroup[_ExceptionT]: ... - - @overload - def derive( - self, __excs: Sequence[_BaseExceptionT] - ) -> BaseExceptionGroup[_BaseExceptionT]: ... - - def derive( - self, __excs: Sequence[_BaseExceptionT] - ) -> BaseExceptionGroup[_BaseExceptionT]: - return BaseExceptionGroup(self.message, __excs) - - def __str__(self) -> str: - suffix = "" if len(self._exceptions) == 1 else "s" - return f"{self.message} ({len(self._exceptions)} sub-exception{suffix})" - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.args[0]!r}, {self.args[1]!r})" - - -class ExceptionGroup(BaseExceptionGroup[_ExceptionT_co], Exception): - def __new__( - cls: type[_ExceptionGroupSelf], - __message: str, - __exceptions: Sequence[_ExceptionT_co], - ) -> _ExceptionGroupSelf: - return super().__new__(cls, __message, __exceptions) - - if TYPE_CHECKING: - - @property - def exceptions( - self, - ) -> tuple[_ExceptionT_co | ExceptionGroup[_ExceptionT_co], ...]: ... - - @overload # type: ignore[override] - def subgroup( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> ExceptionGroup[_ExceptionT] | None: ... - - @overload - def subgroup( - self, __condition: Callable[[_ExceptionT_co | _ExceptionGroupSelf], bool] - ) -> ExceptionGroup[_ExceptionT_co] | None: ... - - def subgroup( - self, - __condition: type[_ExceptionT] - | tuple[type[_ExceptionT], ...] - | Callable[[_ExceptionT_co], bool], - ) -> ExceptionGroup[_ExceptionT] | None: - return super().subgroup(__condition) - - @overload - def split( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> tuple[ - ExceptionGroup[_ExceptionT] | None, ExceptionGroup[_ExceptionT_co] | None - ]: ... - - @overload - def split( - self, __condition: Callable[[_ExceptionT_co | _ExceptionGroupSelf], bool] - ) -> tuple[ - ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None - ]: ... - - def split( - self: _ExceptionGroupSelf, - __condition: type[_ExceptionT] - | tuple[type[_ExceptionT], ...] - | Callable[[_ExceptionT_co], bool], - ) -> tuple[ - ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None - ]: - return super().split(__condition) diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py b/venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py deleted file mode 100644 index 490e2e0cafcd5ed4f6c53da5dbd5b517e10a7baa..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py +++ /dev/null @@ -1,602 +0,0 @@ -# traceback_exception_init() adapted from trio -# -# _ExceptionPrintContext and traceback_exception_format() copied from the standard -# library -from __future__ import annotations - -import collections.abc -import sys -import textwrap -import traceback -from functools import singledispatch -from types import TracebackType -from typing import Any, List, Optional - -from ._exceptions import BaseExceptionGroup - -max_group_width = 15 -max_group_depth = 10 -_cause_message = ( - "\nThe above exception was the direct cause of the following exception:\n\n" -) - -_context_message = ( - "\nDuring handling of the above exception, another exception occurred:\n\n" -) - - -def _format_final_exc_line(etype, value): - valuestr = _safe_string(value, "exception") - if value is None or not valuestr: - line = f"{etype}\n" - else: - line = f"{etype}: {valuestr}\n" - - return line - - -def _safe_string(value, what, func=str): - try: - return func(value) - except BaseException: - return f"<{what} {func.__name__}() failed>" - - -class _ExceptionPrintContext: - def __init__(self): - self.seen = set() - self.exception_group_depth = 0 - self.need_close = False - - def indent(self): - return " " * (2 * self.exception_group_depth) - - def emit(self, text_gen, margin_char=None): - if margin_char is None: - margin_char = "|" - indent_str = self.indent() - if self.exception_group_depth: - indent_str += margin_char + " " - - if isinstance(text_gen, str): - yield textwrap.indent(text_gen, indent_str, lambda line: True) - else: - for text in text_gen: - yield textwrap.indent(text, indent_str, lambda line: True) - - -def exceptiongroup_excepthook( - etype: type[BaseException], value: BaseException, tb: TracebackType | None -) -> None: - sys.stderr.write("".join(traceback.format_exception(etype, value, tb))) - - -class PatchedTracebackException(traceback.TracebackException): - def __init__( - self, - exc_type: type[BaseException], - exc_value: BaseException, - exc_traceback: TracebackType | None, - *, - limit: int | None = None, - lookup_lines: bool = True, - capture_locals: bool = False, - compact: bool = False, - _seen: set[int] | None = None, - ) -> None: - kwargs: dict[str, Any] = {} - if sys.version_info >= (3, 10): - kwargs["compact"] = compact - - is_recursive_call = _seen is not None - if _seen is None: - _seen = set() - _seen.add(id(exc_value)) - - self.stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_traceback), - limit=limit, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - ) - self.exc_type = exc_type - # Capture now to permit freeing resources: only complication is in the - # unofficial API _format_final_exc_line - self._str = _safe_string(exc_value, "exception") - try: - self.__notes__ = getattr(exc_value, "__notes__", None) - except KeyError: - # Workaround for https://github.com/python/cpython/issues/98778 on Python - # <= 3.9, and some 3.10 and 3.11 patch versions. - HTTPError = getattr(sys.modules.get("urllib.error", None), "HTTPError", ()) - if sys.version_info[:2] <= (3, 11) and isinstance(exc_value, HTTPError): - self.__notes__ = None - else: - raise - - if exc_type and issubclass(exc_type, SyntaxError): - # Handle SyntaxError's specially - self.filename = exc_value.filename - lno = exc_value.lineno - self.lineno = str(lno) if lno is not None else None - self.text = exc_value.text - self.offset = exc_value.offset - self.msg = exc_value.msg - if sys.version_info >= (3, 10): - end_lno = exc_value.end_lineno - self.end_lineno = str(end_lno) if end_lno is not None else None - self.end_offset = exc_value.end_offset - elif ( - exc_type - and issubclass(exc_type, (NameError, AttributeError)) - and getattr(exc_value, "name", None) is not None - ): - suggestion = _compute_suggestion_error(exc_value, exc_traceback) - if suggestion: - self._str += f". Did you mean: '{suggestion}'?" - - if lookup_lines: - # Force all lines in the stack to be loaded - for frame in self.stack: - frame.line - - self.__suppress_context__ = ( - exc_value.__suppress_context__ if exc_value is not None else False - ) - - # Convert __cause__ and __context__ to `TracebackExceptions`s, use a - # queue to avoid recursion (only the top-level call gets _seen == None) - if not is_recursive_call: - queue = [(self, exc_value)] - while queue: - te, e = queue.pop() - - if e and e.__cause__ is not None and id(e.__cause__) not in _seen: - cause = PatchedTracebackException( - type(e.__cause__), - e.__cause__, - e.__cause__.__traceback__, - limit=limit, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - _seen=_seen, - ) - else: - cause = None - - if compact: - need_context = ( - cause is None and e is not None and not e.__suppress_context__ - ) - else: - need_context = True - if ( - e - and e.__context__ is not None - and need_context - and id(e.__context__) not in _seen - ): - context = PatchedTracebackException( - type(e.__context__), - e.__context__, - e.__context__.__traceback__, - limit=limit, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - _seen=_seen, - ) - else: - context = None - - # Capture each of the exceptions in the ExceptionGroup along with each - # of their causes and contexts - if e and isinstance(e, BaseExceptionGroup): - exceptions = [] - for exc in e.exceptions: - texc = PatchedTracebackException( - type(exc), - exc, - exc.__traceback__, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - _seen=_seen, - ) - exceptions.append(texc) - else: - exceptions = None - - te.__cause__ = cause - te.__context__ = context - te.exceptions = exceptions - if cause: - queue.append((te.__cause__, e.__cause__)) - if context: - queue.append((te.__context__, e.__context__)) - if exceptions: - queue.extend(zip(te.exceptions, e.exceptions)) - - def format(self, *, chain=True, _ctx=None, **kwargs): - if _ctx is None: - _ctx = _ExceptionPrintContext() - - output = [] - exc = self - if chain: - while exc: - if exc.__cause__ is not None: - chained_msg = _cause_message - chained_exc = exc.__cause__ - elif exc.__context__ is not None and not exc.__suppress_context__: - chained_msg = _context_message - chained_exc = exc.__context__ - else: - chained_msg = None - chained_exc = None - - output.append((chained_msg, exc)) - exc = chained_exc - else: - output.append((None, exc)) - - for msg, exc in reversed(output): - if msg is not None: - yield from _ctx.emit(msg) - if getattr(exc, "exceptions", None) is None: - if exc.stack: - yield from _ctx.emit("Traceback (most recent call last):\n") - yield from _ctx.emit(exc.stack.format()) - yield from _ctx.emit(exc.format_exception_only()) - elif _ctx.exception_group_depth > max_group_depth: - # exception group, but depth exceeds limit - yield from _ctx.emit(f"... (max_group_depth is {max_group_depth})\n") - else: - # format exception group - is_toplevel = _ctx.exception_group_depth == 0 - if is_toplevel: - _ctx.exception_group_depth += 1 - - if exc.stack: - yield from _ctx.emit( - "Exception Group Traceback (most recent call last):\n", - margin_char="+" if is_toplevel else None, - ) - yield from _ctx.emit(exc.stack.format()) - - yield from _ctx.emit(exc.format_exception_only()) - num_excs = len(exc.exceptions) - if num_excs <= max_group_width: - n = num_excs - else: - n = max_group_width + 1 - _ctx.need_close = False - for i in range(n): - last_exc = i == n - 1 - if last_exc: - # The closing frame may be added by a recursive call - _ctx.need_close = True - - if max_group_width is not None: - truncated = i >= max_group_width - else: - truncated = False - title = f"{i + 1}" if not truncated else "..." - yield ( - _ctx.indent() - + ("+-" if i == 0 else " ") - + f"+---------------- {title} ----------------\n" - ) - _ctx.exception_group_depth += 1 - if not truncated: - yield from exc.exceptions[i].format(chain=chain, _ctx=_ctx) - else: - remaining = num_excs - max_group_width - plural = "s" if remaining > 1 else "" - yield from _ctx.emit( - f"and {remaining} more exception{plural}\n" - ) - - if last_exc and _ctx.need_close: - yield _ctx.indent() + "+------------------------------------\n" - _ctx.need_close = False - _ctx.exception_group_depth -= 1 - - if is_toplevel: - assert _ctx.exception_group_depth == 1 - _ctx.exception_group_depth = 0 - - def format_exception_only(self, **kwargs): - """Format the exception part of the traceback. - The return value is a generator of strings, each ending in a newline. - Normally, the generator emits a single string; however, for - SyntaxError exceptions, it emits several lines that (when - printed) display detailed information about where the syntax - error occurred. - The message indicating which exception occurred is always the last - string in the output. - """ - if self.exc_type is None: - yield traceback._format_final_exc_line(None, self._str) - return - - stype = self.exc_type.__qualname__ - smod = self.exc_type.__module__ - if smod not in ("__main__", "builtins"): - if not isinstance(smod, str): - smod = "" - stype = smod + "." + stype - - if not issubclass(self.exc_type, SyntaxError): - yield _format_final_exc_line(stype, self._str) - elif traceback_exception_format_syntax_error is not None: - yield from traceback_exception_format_syntax_error(self, stype) - else: - yield from traceback_exception_original_format_exception_only(self) - - notes = getattr(self, "__notes__", None) - if isinstance(notes, collections.abc.Sequence): - for note in notes: - note = _safe_string(note, "note") - yield from [line + "\n" for line in note.split("\n")] - elif notes is not None: - yield _safe_string(notes, "__notes__", func=repr) - - -traceback_exception_original_format = traceback.TracebackException.format -traceback_exception_original_format_exception_only = ( - traceback.TracebackException.format_exception_only -) -traceback_exception_format_syntax_error = getattr( - traceback.TracebackException, "_format_syntax_error", None -) -if sys.excepthook is sys.__excepthook__: - traceback.TracebackException.__init__ = ( # type: ignore[assignment] - PatchedTracebackException.__init__ - ) - traceback.TracebackException.format = ( # type: ignore[assignment] - PatchedTracebackException.format - ) - traceback.TracebackException.format_exception_only = ( # type: ignore[assignment] - PatchedTracebackException.format_exception_only - ) - sys.excepthook = exceptiongroup_excepthook - -# Ubuntu's system Python has a sitecustomize.py file that imports -# apport_python_hook and replaces sys.excepthook. -# -# The custom hook captures the error for crash reporting, and then calls -# sys.__excepthook__ to actually print the error. -# -# We don't mind it capturing the error for crash reporting, but we want to -# take over printing the error. So we monkeypatch the apport_python_hook -# module so that instead of calling sys.__excepthook__, it calls our custom -# hook. -# -# More details: https://github.com/python-trio/trio/issues/1065 -if getattr(sys.excepthook, "__name__", None) in ( - "apport_excepthook", - # on ubuntu 22.10 the hook was renamed to partial_apport_excepthook - "partial_apport_excepthook", -): - # patch traceback like above - traceback.TracebackException.__init__ = ( # type: ignore[assignment] - PatchedTracebackException.__init__ - ) - traceback.TracebackException.format = ( # type: ignore[assignment] - PatchedTracebackException.format - ) - traceback.TracebackException.format_exception_only = ( # type: ignore[assignment] - PatchedTracebackException.format_exception_only - ) - - from types import ModuleType - - import apport_python_hook - - # monkeypatch the sys module that apport has imported - fake_sys = ModuleType("exceptiongroup_fake_sys") - fake_sys.__dict__.update(sys.__dict__) - fake_sys.__excepthook__ = exceptiongroup_excepthook - apport_python_hook.sys = fake_sys - - -@singledispatch -def format_exception_only(__exc: BaseException, **kwargs: Any) -> List[str]: - return list( - PatchedTracebackException( - type(__exc), __exc, None, compact=True - ).format_exception_only() - ) - - -@format_exception_only.register -def _(__exc: type, value: BaseException, **kwargs: Any) -> List[str]: - return format_exception_only(value) - - -@singledispatch -def format_exception( - __exc: BaseException, limit: Optional[int] = None, chain: bool = True, **kwargs: Any -) -> List[str]: - return list( - PatchedTracebackException( - type(__exc), __exc, __exc.__traceback__, limit=limit, compact=True - ).format(chain=chain) - ) - - -@format_exception.register -def _( - __exc: type, - value: BaseException, - tb: TracebackType, - limit: Optional[int] = None, - chain: bool = True, - **kwargs: Any, -) -> List[str]: - return format_exception(value, limit, chain) - - -@singledispatch -def print_exception( - __exc: BaseException, - limit: Optional[int] = None, - file: Any = None, - chain: bool = True, - **kwargs: Any, -) -> None: - if file is None: - file = sys.stderr - - for line in PatchedTracebackException( - type(__exc), __exc, __exc.__traceback__, limit=limit - ).format(chain=chain): - print(line, file=file, end="") - - -@print_exception.register -def _( - __exc: type, - value: BaseException, - tb: TracebackType, - limit: Optional[int] = None, - file: Any = None, - chain: bool = True, -) -> None: - print_exception(value, limit, file, chain) - - -def print_exc( - limit: Optional[int] = None, - file: Any | None = None, - chain: bool = True, -) -> None: - value = sys.exc_info()[1] - print_exception(value, limit, file, chain) - - -# Python levenshtein edit distance code for NameError/AttributeError -# suggestions, backported from 3.12 - -_MAX_CANDIDATE_ITEMS = 750 -_MAX_STRING_SIZE = 40 -_MOVE_COST = 2 -_CASE_COST = 1 -_SENTINEL = object() - - -def _substitution_cost(ch_a, ch_b): - if ch_a == ch_b: - return 0 - if ch_a.lower() == ch_b.lower(): - return _CASE_COST - return _MOVE_COST - - -def _compute_suggestion_error(exc_value, tb): - wrong_name = getattr(exc_value, "name", None) - if wrong_name is None or not isinstance(wrong_name, str): - return None - if isinstance(exc_value, AttributeError): - obj = getattr(exc_value, "obj", _SENTINEL) - if obj is _SENTINEL: - return None - obj = exc_value.obj - try: - d = dir(obj) - except Exception: - return None - else: - assert isinstance(exc_value, NameError) - # find most recent frame - if tb is None: - return None - while tb.tb_next is not None: - tb = tb.tb_next - frame = tb.tb_frame - - d = list(frame.f_locals) + list(frame.f_globals) + list(frame.f_builtins) - if len(d) > _MAX_CANDIDATE_ITEMS: - return None - wrong_name_len = len(wrong_name) - if wrong_name_len > _MAX_STRING_SIZE: - return None - best_distance = wrong_name_len - suggestion = None - for possible_name in d: - if possible_name == wrong_name: - # A missing attribute is "found". Don't suggest it (see GH-88821). - continue - # No more than 1/3 of the involved characters should need changed. - max_distance = (len(possible_name) + wrong_name_len + 3) * _MOVE_COST // 6 - # Don't take matches we've already beaten. - max_distance = min(max_distance, best_distance - 1) - current_distance = _levenshtein_distance( - wrong_name, possible_name, max_distance - ) - if current_distance > max_distance: - continue - if not suggestion or current_distance < best_distance: - suggestion = possible_name - best_distance = current_distance - return suggestion - - -def _levenshtein_distance(a, b, max_cost): - # A Python implementation of Python/suggestions.c:levenshtein_distance. - - # Both strings are the same - if a == b: - return 0 - - # Trim away common affixes - pre = 0 - while a[pre:] and b[pre:] and a[pre] == b[pre]: - pre += 1 - a = a[pre:] - b = b[pre:] - post = 0 - while a[: post or None] and b[: post or None] and a[post - 1] == b[post - 1]: - post -= 1 - a = a[: post or None] - b = b[: post or None] - if not a or not b: - return _MOVE_COST * (len(a) + len(b)) - if len(a) > _MAX_STRING_SIZE or len(b) > _MAX_STRING_SIZE: - return max_cost + 1 - - # Prefer shorter buffer - if len(b) < len(a): - a, b = b, a - - # Quick fail when a match is impossible - if (len(b) - len(a)) * _MOVE_COST > max_cost: - return max_cost + 1 - - # Instead of producing the whole traditional len(a)-by-len(b) - # matrix, we can update just one row in place. - # Initialize the buffer row - row = list(range(_MOVE_COST, _MOVE_COST * (len(a) + 1), _MOVE_COST)) - - result = 0 - for bindex in range(len(b)): - bchar = b[bindex] - distance = result = bindex * _MOVE_COST - minimum = sys.maxsize - for index in range(len(a)): - # 1) Previous distance in this row is cost(b[:b_index], a[:index]) - substitute = distance + _substitution_cost(bchar, a[index]) - # 2) cost(b[:b_index], a[:index+1]) from previous row - distance = row[index] - # 3) existing result is cost(b[:b_index+1], a[index]) - - insert_delete = min(result, distance) + _MOVE_COST - result = min(insert_delete, substitute) - - # cost(b[:b_index+1], a[:index+1]) - row[index] = result - if result < minimum: - minimum = result - if minimum > max_cost: - # Everything in this row is too big, so bail early. - return max_cost + 1 - return result diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py b/venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py deleted file mode 100644 index 11467eeda9b317cbf5d378beea30e31a51d35d1c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -import sys -from contextlib import AbstractContextManager -from types import TracebackType -from typing import TYPE_CHECKING, Optional, Type, cast - -if sys.version_info < (3, 11): - from ._exceptions import BaseExceptionGroup - -if TYPE_CHECKING: - # requires python 3.9 - BaseClass = AbstractContextManager[None] -else: - BaseClass = AbstractContextManager - - -class suppress(BaseClass): - """Backport of :class:`contextlib.suppress` from Python 3.12.1.""" - - def __init__(self, *exceptions: type[BaseException]): - self._exceptions = exceptions - - def __enter__(self) -> None: - pass - - def __exit__( - self, - exctype: Optional[Type[BaseException]], - excinst: Optional[BaseException], - exctb: Optional[TracebackType], - ) -> bool: - # Unlike isinstance and issubclass, CPython exception handling - # currently only looks at the concrete type hierarchy (ignoring - # the instance and subclass checking hooks). While Guido considers - # that a bug rather than a feature, it's a fairly hard one to fix - # due to various internal implementation details. suppress provides - # the simpler issubclass based semantics, rather than trying to - # exactly reproduce the limitations of the CPython interpreter. - # - # See http://bugs.python.org/issue12029 for more details - if exctype is None: - return False - - if issubclass(exctype, self._exceptions): - return True - - if issubclass(exctype, BaseExceptionGroup): - match, rest = cast(BaseExceptionGroup, excinst).split(self._exceptions) - if rest is None: - return True - - raise rest - - return False diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/_version.py b/venv/lib/python3.10/site-packages/exceptiongroup/_version.py deleted file mode 100644 index ebbbcb239f0fb8240eada674229f81e66f1c7022..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/exceptiongroup/_version.py +++ /dev/null @@ -1,34 +0,0 @@ -# file generated by setuptools-scm -# don't change, don't track in version control - -__all__ = [ - "__version__", - "__version_tuple__", - "version", - "version_tuple", - "__commit_id__", - "commit_id", -] - -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import Tuple - from typing import Union - - VERSION_TUPLE = Tuple[Union[int, str], ...] - COMMIT_ID = Union[str, None] -else: - VERSION_TUPLE = object - COMMIT_ID = object - -version: str -__version__: str -__version_tuple__: VERSION_TUPLE -version_tuple: VERSION_TUPLE -commit_id: COMMIT_ID -__commit_id__: COMMIT_ID - -__version__ = version = '1.3.1' -__version_tuple__ = version_tuple = (1, 3, 1) - -__commit_id__ = commit_id = None diff --git a/venv/lib/python3.10/site-packages/exceptiongroup/py.typed b/venv/lib/python3.10/site-packages/exceptiongroup/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/METADATA b/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/METADATA deleted file mode 100644 index 7a9022a30ed6fd46c28fed49f956e581b9a2b092..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/METADATA +++ /dev/null @@ -1,38 +0,0 @@ -Metadata-Version: 2.4 -Name: filelock -Version: 3.24.3 -Summary: A platform independent file lock. -Project-URL: Documentation, https://py-filelock.readthedocs.io -Project-URL: Homepage, https://github.com/tox-dev/py-filelock -Project-URL: Source, https://github.com/tox-dev/py-filelock -Project-URL: Tracker, https://github.com/tox-dev/py-filelock/issues -Maintainer-email: Bernát Gábor -License-Expression: MIT -License-File: LICENSE -Keywords: application,cache,directory,log,user -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: System -Requires-Python: >=3.10 -Description-Content-Type: text/markdown - -# filelock - -[![PyPI](https://img.shields.io/pypi/v/filelock)](https://pypi.org/project/filelock/) -[![Supported Python versions](https://img.shields.io/pypi/pyversions/filelock.svg)](https://pypi.org/project/filelock/) -[![Documentation status](https://readthedocs.org/projects/py-filelock/badge/?version=latest)](https://py-filelock.readthedocs.io/en/latest/?badge=latest) -[![Downloads](https://static.pepy.tech/badge/filelock/month)](https://pepy.tech/project/filelock) -[![check](https://github.com/tox-dev/py-filelock/actions/workflows/check.yaml/badge.svg)](https://github.com/tox-dev/py-filelock/actions/workflows/check.yaml) - -For more information checkout the [official documentation](https://py-filelock.readthedocs.io/en/latest/index.html). diff --git a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/RECORD b/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/RECORD deleted file mode 100644 index a262043f331ff21553ce3b2182614c7bcac2534c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/RECORD +++ /dev/null @@ -1,26 +0,0 @@ -filelock-3.24.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -filelock-3.24.3.dist-info/METADATA,sha256=2SzY43viecqbmVNOokZgXcYTE04sufy5Rjf6wZTMWC4,1977 -filelock-3.24.3.dist-info/RECORD,, -filelock-3.24.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87 -filelock-3.24.3.dist-info/licenses/LICENSE,sha256=YIyJ1QYK6ZIa3M8yNmlbxlSplG4SMj72wCHfoE4pTUg,1088 -filelock/__init__.py,sha256=12pKiL8AjSCkmWLozJhcCg6qQY70_XizYh9AHUvzZ1Q,2009 -filelock/__pycache__/__init__.cpython-310.pyc,, -filelock/__pycache__/_api.cpython-310.pyc,, -filelock/__pycache__/_error.cpython-310.pyc,, -filelock/__pycache__/_read_write.cpython-310.pyc,, -filelock/__pycache__/_soft.cpython-310.pyc,, -filelock/__pycache__/_unix.cpython-310.pyc,, -filelock/__pycache__/_util.cpython-310.pyc,, -filelock/__pycache__/_windows.cpython-310.pyc,, -filelock/__pycache__/asyncio.cpython-310.pyc,, -filelock/__pycache__/version.cpython-310.pyc,, -filelock/_api.py,sha256=l8P7bqosgleI3vPn8OVGQ0-sa2d3WVhvM_j9SCCcTx4,21159 -filelock/_error.py,sha256=mnelOh0EVyVeskG3rksL4kW3OArL4TMb2-PwmzQWIFg,788 -filelock/_read_write.py,sha256=o6pcX04--nXFspDXtV_J113EDH_-rzz-Hvp-cmH76P4,15313 -filelock/_soft.py,sha256=8aSSoyLZjBDV-ql3LJt_Ec_kg7ywHDE8ZZFcCtVWxQ8,4665 -filelock/_unix.py,sha256=DL0mk9OAE21wY-uhdClJ2ezBUFfi-vNszdBJCw7slqE,4233 -filelock/_util.py,sha256=wPf-LvzmdHWHw4DinDeVJlB0GNVOYGNUeNKSnHBQuUU,1716 -filelock/_windows.py,sha256=-CEBIFfFPwmfSSmTmbbGzgUR30E0jBacBW9j4_ER0YM,3508 -filelock/asyncio.py,sha256=NvrDsqS095NZc16l_OjBQcTY-D6xB4Vy7AK3ni8tr8A,13943 -filelock/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -filelock/version.py,sha256=cEVcBJgzKOmekaY1NFrR1sXy1-sBY4F7inrTVfovZUA,706 diff --git a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/WHEEL b/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/WHEEL deleted file mode 100644 index ae8ec1bdaa94d726ceb907542d76cbd5d38cafcd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.28.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/licenses/LICENSE deleted file mode 100644 index 291919c0b6f41d014767f6c877af9f7595fcff99..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock-3.24.3.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 Bernát Gábor and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/venv/lib/python3.10/site-packages/filelock/__init__.py b/venv/lib/python3.10/site-packages/filelock/__init__.py deleted file mode 100644 index ce3c8e8a2df62956740156560302a56f5ba7384b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/__init__.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -A platform independent file lock that supports the with-statement. - -.. autodata:: filelock.__version__ - :no-value: - -""" - -from __future__ import annotations - -import sys -import warnings -from typing import TYPE_CHECKING - -from ._api import AcquireReturnProxy, BaseFileLock -from ._error import Timeout - -try: - from ._read_write import ReadWriteLock -except ImportError: # sqlite3 may be unavailable if Python was built without it or the C library is missing - ReadWriteLock = None # type: ignore[assignment, misc] - -from ._soft import SoftFileLock -from ._unix import UnixFileLock, has_fcntl -from ._windows import WindowsFileLock -from .asyncio import ( - AsyncAcquireReturnProxy, - AsyncSoftFileLock, - AsyncUnixFileLock, - AsyncWindowsFileLock, - BaseAsyncFileLock, -) -from .version import version - -#: version of the project as a string -__version__: str = version - - -if sys.platform == "win32": # pragma: win32 cover - _FileLock: type[BaseFileLock] = WindowsFileLock - _AsyncFileLock: type[BaseAsyncFileLock] = AsyncWindowsFileLock -else: # pragma: win32 no cover # noqa: PLR5501 - if has_fcntl: - _FileLock: type[BaseFileLock] = UnixFileLock - _AsyncFileLock: type[BaseAsyncFileLock] = AsyncUnixFileLock - else: - _FileLock = SoftFileLock - _AsyncFileLock = AsyncSoftFileLock - if warnings is not None: - warnings.warn("only soft file lock is available", stacklevel=2) - -if TYPE_CHECKING: - FileLock = SoftFileLock - AsyncFileLock = AsyncSoftFileLock -else: - #: Alias for the lock, which should be used for the current platform. - FileLock = _FileLock - AsyncFileLock = _AsyncFileLock - - -__all__ = [ - "AcquireReturnProxy", - "AsyncAcquireReturnProxy", - "AsyncFileLock", - "AsyncSoftFileLock", - "AsyncUnixFileLock", - "AsyncWindowsFileLock", - "BaseAsyncFileLock", - "BaseFileLock", - "FileLock", - "ReadWriteLock", - "SoftFileLock", - "Timeout", - "UnixFileLock", - "WindowsFileLock", - "__version__", -] diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 2b49b029ba73ff9559ed6ee15983d9fb0067ab10..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/_api.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/_api.cpython-310.pyc deleted file mode 100644 index d5dc4673c45ba906a256e42b4487307d1de15507..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/_api.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/_error.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/_error.cpython-310.pyc deleted file mode 100644 index 93faf06e88240f1a6d651e92dfcd35e6341c3bfa..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/_error.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/_read_write.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/_read_write.cpython-310.pyc deleted file mode 100644 index c3e3fe983835628b7324e211cae3ab8b70633534..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/_read_write.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/_soft.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/_soft.cpython-310.pyc deleted file mode 100644 index 37ae473189f71f6fe254be10f777754ca629904b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/_soft.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/_unix.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/_unix.cpython-310.pyc deleted file mode 100644 index 028a76b1f86a5049ae89167a3454f57bbab11660..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/_unix.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/_util.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/_util.cpython-310.pyc deleted file mode 100644 index 0a7c1213c4bc47abc3e16b31aa70882c5a64ebcd..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/_util.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/_windows.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/_windows.cpython-310.pyc deleted file mode 100644 index d71de13082e0914131080c4d6e5b478d9027f50e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/_windows.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/asyncio.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/asyncio.cpython-310.pyc deleted file mode 100644 index 7c03d7193a6c1f3ea05eb18d0160989b82af9c78..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/asyncio.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/__pycache__/version.cpython-310.pyc b/venv/lib/python3.10/site-packages/filelock/__pycache__/version.cpython-310.pyc deleted file mode 100644 index 88d6c525cc1174e4854a629edc9fe82088841cc8..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/filelock/__pycache__/version.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/filelock/_api.py b/venv/lib/python3.10/site-packages/filelock/_api.py deleted file mode 100644 index 3bcc94cdf258f808e3f637186182c05dc961203c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/_api.py +++ /dev/null @@ -1,578 +0,0 @@ -from __future__ import annotations - -import contextlib -import inspect -import logging -import os -import pathlib -import sys -import time -import warnings -from abc import ABCMeta, abstractmethod -from dataclasses import dataclass -from threading import local -from typing import TYPE_CHECKING, Any, cast -from weakref import WeakValueDictionary - -from ._error import Timeout - -#: Sentinel indicating that no explicit file permission mode was passed. -#: When used, lock files are created with 0o666 (letting umask and default ACLs control the final permissions) -#: and fchmod is skipped so that POSIX default ACL inheritance is preserved. -_UNSET_FILE_MODE: int = -1 - -if TYPE_CHECKING: - from collections.abc import Callable - from types import TracebackType - - from ._read_write import ReadWriteLock - - if sys.version_info >= (3, 11): # pragma: no cover (py311+) - from typing import Self - else: # pragma: no cover ( None: - super().__init__() - self.held: dict[str, int] = {} - - -_registry = _ThreadLocalRegistry() - - -# This is a helper class which is returned by :meth:`BaseFileLock.acquire` and wraps the lock to make sure __enter__ -# is not called twice when entering the with statement. If we would simply return *self*, the lock would be acquired -# again in the *__enter__* method of the BaseFileLock, but not released again automatically. issue #37 (memory leak) -class AcquireReturnProxy: - """A context-aware object that will release the lock file when exiting.""" - - def __init__(self, lock: BaseFileLock | ReadWriteLock) -> None: - self.lock: BaseFileLock | ReadWriteLock = lock - - def __enter__(self) -> BaseFileLock | ReadWriteLock: - return self.lock - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - self.lock.release() - - -@dataclass -class FileLockContext: - """A dataclass which holds the context for a ``BaseFileLock`` object.""" - - # The context is held in a separate class to allow optional use of thread local storage via the - # ThreadLocalFileContext class. - - #: The path to the lock file. - lock_file: str - - #: The default timeout value. - timeout: float - - #: The mode for the lock files - mode: int - - #: Whether the lock should be blocking or not - blocking: bool - - #: The default polling interval value. - poll_interval: float - - #: The lock lifetime in seconds; ``None`` means the lock never expires. - lifetime: float | None = None - - #: The file descriptor for the *_lock_file* as it is returned by the os.open() function, not None when lock held - lock_file_fd: int | None = None - - #: The lock counter is used for implementing the nested locking mechanism. - lock_counter: int = 0 # When the lock is acquired is increased and the lock is only released, when this value is 0 - - -class ThreadLocalFileContext(FileLockContext, local): - """A thread local version of the ``FileLockContext`` class.""" - - -class FileLockMeta(ABCMeta): - _instances: WeakValueDictionary[str, BaseFileLock] - - def __call__( # noqa: PLR0913 - cls, - lock_file: str | os.PathLike[str], - timeout: float = -1, - mode: int = _UNSET_FILE_MODE, - thread_local: bool = True, # noqa: FBT001, FBT002 - *, - blocking: bool = True, - is_singleton: bool = False, - poll_interval: float = 0.05, - lifetime: float | None = None, - **kwargs: Any, # capture remaining kwargs for subclasses # noqa: ANN401 - ) -> BaseFileLock: - if is_singleton: - instance = cls._instances.get(str(lock_file)) - if instance: - params_to_check = { - "thread_local": (thread_local, instance.is_thread_local()), - "timeout": (timeout, instance.timeout), - "mode": (mode, instance._context.mode), # noqa: SLF001 - "blocking": (blocking, instance.blocking), - "poll_interval": (poll_interval, instance.poll_interval), - "lifetime": (lifetime, instance.lifetime), - } - - non_matching_params = { - name: (passed_param, set_param) - for name, (passed_param, set_param) in params_to_check.items() - if passed_param != set_param - } - if not non_matching_params: - return cast("BaseFileLock", instance) - - # parameters do not match; raise error - msg = "Singleton lock instances cannot be initialized with differing arguments" - msg += "\nNon-matching arguments: " - for param_name, (passed_param, set_param) in non_matching_params.items(): - msg += f"\n\t{param_name} (existing lock has {set_param} but {passed_param} was passed)" - raise ValueError(msg) - - # Workaround to make `__init__`'s params optional in subclasses - # E.g. virtualenv changes the signature of the `__init__` method in the `BaseFileLock` class descendant - # (https://github.com/tox-dev/filelock/pull/340) - - all_params = { - "timeout": timeout, - "mode": mode, - "thread_local": thread_local, - "blocking": blocking, - "is_singleton": is_singleton, - "poll_interval": poll_interval, - "lifetime": lifetime, - **kwargs, - } - - present_params = inspect.signature(cls.__init__).parameters - init_params = {key: value for key, value in all_params.items() if key in present_params} - - instance = super().__call__(lock_file, **init_params) - - if is_singleton: - cls._instances[str(lock_file)] = instance - - return cast("BaseFileLock", instance) - - -class BaseFileLock(contextlib.ContextDecorator, metaclass=FileLockMeta): - """ - Abstract base class for a file lock object. - - Provides a reentrant, cross-process exclusive lock backed by OS-level primitives. Subclasses implement the actual - locking mechanism (:class:`UnixFileLock `, :class:`WindowsFileLock - `, :class:`SoftFileLock `). - - """ - - _instances: WeakValueDictionary[str, BaseFileLock] - - def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None: - """Setup unique state for lock subclasses.""" - super().__init_subclass__(**kwargs) - cls._instances = WeakValueDictionary() - - def __init__( # noqa: PLR0913 - self, - lock_file: str | os.PathLike[str], - timeout: float = -1, - mode: int = _UNSET_FILE_MODE, - thread_local: bool = True, # noqa: FBT001, FBT002 - *, - blocking: bool = True, - is_singleton: bool = False, - poll_interval: float = 0.05, - lifetime: float | None = None, - ) -> None: - """ - Create a new lock object. - - :param lock_file: path to the file - :param timeout: default timeout when acquiring the lock, in seconds. It will be used as fallback value in the - acquire method, if no timeout value (``None``) is given. If you want to disable the timeout, set it to a - negative value. A timeout of 0 means that there is exactly one attempt to acquire the file lock. - :param mode: file permissions for the lockfile. When not specified, the OS controls permissions via umask and - default ACLs, preserving POSIX default ACL inheritance in shared directories. - :param thread_local: Whether this object's internal context should be thread local or not. If this is set to - ``False`` then the lock will be reentrant across threads. - :param blocking: whether the lock should be blocking or not - :param is_singleton: If this is set to ``True`` then only one instance of this class will be created per lock - file. This is useful if you want to use the lock object for reentrant locking without needing to pass the - same object around. - :param poll_interval: default interval for polling the lock file, in seconds. It will be used as fallback value - in the acquire method, if no poll_interval value (``None``) is given. - :param lifetime: maximum time in seconds a lock can be held before it is considered expired. When set, a waiting - process will break a lock whose file modification time is older than ``lifetime`` seconds. ``None`` (the - default) means locks never expire. - - """ - self._is_thread_local = thread_local - self._is_singleton = is_singleton - - # Create the context. Note that external code should not work with the context directly and should instead use - # properties of this class. - kwargs: dict[str, Any] = { - "lock_file": os.fspath(lock_file), - "timeout": timeout, - "mode": mode, - "blocking": blocking, - "poll_interval": poll_interval, - "lifetime": lifetime, - } - self._context: FileLockContext = (ThreadLocalFileContext if thread_local else FileLockContext)(**kwargs) - - def is_thread_local(self) -> bool: - """:returns: a flag indicating if this lock is thread local or not""" - return self._is_thread_local - - @property - def is_singleton(self) -> bool: - """ - :returns: a flag indicating if this lock is singleton or not - - .. versionadded:: 3.13.0 - - """ - return self._is_singleton - - @property - def lock_file(self) -> str: - """:returns: path to the lock file""" - return self._context.lock_file - - @property - def timeout(self) -> float: - """ - :returns: the default timeout value, in seconds - - .. versionadded:: 2.0.0 - - """ - return self._context.timeout - - @timeout.setter - def timeout(self, value: float | str) -> None: - """ - Change the default timeout value. - - :param value: the new value, in seconds - - """ - self._context.timeout = float(value) - - @property - def blocking(self) -> bool: - """ - :returns: whether the locking is blocking or not - - .. versionadded:: 3.14.0 - - """ - return self._context.blocking - - @blocking.setter - def blocking(self, value: bool) -> None: - """ - Change the default blocking value. - - :param value: the new value as bool - - """ - self._context.blocking = value - - @property - def poll_interval(self) -> float: - """ - :returns: the default polling interval, in seconds - - .. versionadded:: 3.24.0 - - """ - return self._context.poll_interval - - @poll_interval.setter - def poll_interval(self, value: float) -> None: - """ - Change the default polling interval. - - :param value: the new value, in seconds - - """ - self._context.poll_interval = value - - @property - def lifetime(self) -> float | None: - """ - :returns: the lock lifetime in seconds, or ``None`` if the lock never expires - - .. versionadded:: 3.24.0 - - """ - return self._context.lifetime - - @lifetime.setter - def lifetime(self, value: float | None) -> None: - """ - Change the lock lifetime. - - :param value: the new value in seconds, or ``None`` to disable expiration - - """ - self._context.lifetime = value - - @property - def mode(self) -> int: - """:returns: the file permissions for the lockfile""" - return 0o644 if self._context.mode == _UNSET_FILE_MODE else self._context.mode - - @property - def has_explicit_mode(self) -> bool: - """:returns: whether the file permissions were explicitly set""" - return self._context.mode != _UNSET_FILE_MODE - - def _open_mode(self) -> int: - """:returns: the mode for os.open() — 0o666 when unset (let umask/ACLs decide), else the explicit mode""" - return 0o666 if self._context.mode == _UNSET_FILE_MODE else self._context.mode - - def _try_break_expired_lock(self) -> None: - """Remove the lock file if its modification time exceeds the configured :attr:`lifetime`.""" - if (lifetime := self._context.lifetime) is None: - return - with contextlib.suppress(OSError): - if time.time() - pathlib.Path(self.lock_file).stat().st_mtime < lifetime: - return - break_path = f"{self.lock_file}.break.{os.getpid()}" - pathlib.Path(self.lock_file).rename(break_path) - pathlib.Path(break_path).unlink() - - @abstractmethod - def _acquire(self) -> None: - """If the file lock could be acquired, self._context.lock_file_fd holds the file descriptor of the lock file.""" - raise NotImplementedError - - @abstractmethod - def _release(self) -> None: - """Releases the lock and sets self._context.lock_file_fd to None.""" - raise NotImplementedError - - @property - def is_locked(self) -> bool: - """ - :returns: A boolean indicating if the lock file is holding the lock currently. - - .. versionchanged:: 2.0.0 - - This was previously a method and is now a property. - - """ - return self._context.lock_file_fd is not None - - @property - def lock_counter(self) -> int: - """:returns: The number of times this lock has been acquired (but not yet released).""" - return self._context.lock_counter - - @staticmethod - def _check_give_up( # noqa: PLR0913 - lock_id: int, - lock_filename: str, - *, - blocking: bool, - cancel_check: Callable[[], bool] | None, - timeout: float, - start_time: float, - ) -> bool: - if blocking is False: - _LOGGER.debug("Failed to immediately acquire lock %s on %s", lock_id, lock_filename) - return True - if cancel_check is not None and cancel_check(): - _LOGGER.debug("Cancellation requested for lock %s on %s", lock_id, lock_filename) - return True - if 0 <= timeout < time.perf_counter() - start_time: - _LOGGER.debug("Timeout on acquiring lock %s on %s", lock_id, lock_filename) - return True - return False - - def acquire( # noqa: C901 - self, - timeout: float | None = None, - poll_interval: float | None = None, - *, - poll_intervall: float | None = None, - blocking: bool | None = None, - cancel_check: Callable[[], bool] | None = None, - ) -> AcquireReturnProxy: - """ - Try to acquire the file lock. - - :param timeout: maximum wait time for acquiring the lock, ``None`` means use the default :attr:`~timeout` is and - if ``timeout < 0``, there is no timeout and this method will block until the lock could be acquired - :param poll_interval: interval of trying to acquire the lock file, ``None`` means use the default - :attr:`~poll_interval` - :param poll_intervall: deprecated, kept for backwards compatibility, use ``poll_interval`` instead - :param blocking: defaults to True. If False, function will return immediately if it cannot obtain a lock on the - first attempt. Otherwise, this method will block until the timeout expires or the lock is acquired. - :param cancel_check: a callable returning ``True`` when the acquisition should be canceled. Checked on each poll - iteration. When triggered, raises :class:`~Timeout` just like an expired timeout. - - :returns: a context object that will unlock the file when the context is exited - - :raises Timeout: if fails to acquire lock within the timeout period - - .. code-block:: python - - # You can use this method in the context manager (recommended) - with lock.acquire(): - pass - - # Or use an equivalent try-finally construct: - lock.acquire() - try: - pass - finally: - lock.release() - - .. versionchanged:: 2.0.0 - - This method returns now a *proxy* object instead of *self*, so that it can be used in a with statement - without side effects. - - """ - # Use the default timeout, if no timeout is provided. - if timeout is None: - timeout = self._context.timeout - - if blocking is None: - blocking = self._context.blocking - - if poll_intervall is not None: - msg = "use poll_interval instead of poll_intervall" - warnings.warn(msg, DeprecationWarning, stacklevel=2) - poll_interval = poll_intervall - - poll_interval = poll_interval if poll_interval is not None else self._context.poll_interval - - # Increment the number right at the beginning. We can still undo it, if something fails. - self._context.lock_counter += 1 - - lock_id = id(self) - lock_filename = self.lock_file - canonical = _canonical(lock_filename) - - would_block = self._context.lock_counter == 1 and not self.is_locked and timeout < 0 and blocking - if would_block and (existing := _registry.held.get(canonical)) is not None and existing != lock_id: - self._context.lock_counter -= 1 - msg = ( - f"Deadlock: lock '{lock_filename}' is already held by a different " - f"FileLock instance in this thread. Use is_singleton=True to " - f"enable reentrant locking across instances." - ) - raise RuntimeError(msg) - - start_time = time.perf_counter() - try: - while True: - if not self.is_locked: - self._try_break_expired_lock() - _LOGGER.debug("Attempting to acquire lock %s on %s", lock_id, lock_filename) - self._acquire() - if self.is_locked: - _LOGGER.debug("Lock %s acquired on %s", lock_id, lock_filename) - break - if self._check_give_up( - lock_id, - lock_filename, - blocking=blocking, - cancel_check=cancel_check, - timeout=timeout, - start_time=start_time, - ): - raise Timeout(lock_filename) # noqa: TRY301 - msg = "Lock %s not acquired on %s, waiting %s seconds ..." - _LOGGER.debug(msg, lock_id, lock_filename, poll_interval) - time.sleep(poll_interval) - except BaseException: - self._context.lock_counter = max(0, self._context.lock_counter - 1) - if self._context.lock_counter == 0: - _registry.held.pop(canonical, None) - raise - if self._context.lock_counter == 1: - _registry.held[canonical] = lock_id - return AcquireReturnProxy(lock=self) - - def release(self, force: bool = False) -> None: # noqa: FBT001, FBT002 - """ - Release the file lock. The lock is only completely released when the lock counter reaches 0. The lock file - itself is not automatically deleted. - - :param force: If true, the lock counter is ignored and the lock is released in every case. - - """ - if self.is_locked: - self._context.lock_counter -= 1 - - if self._context.lock_counter == 0 or force: - lock_id, lock_filename = id(self), self.lock_file - - _LOGGER.debug("Attempting to release lock %s on %s", lock_id, lock_filename) - self._release() - self._context.lock_counter = 0 - _registry.held.pop(_canonical(lock_filename), None) - _LOGGER.debug("Lock %s released on %s", lock_id, lock_filename) - - def __enter__(self) -> Self: - """ - Acquire the lock. - - :returns: the lock object - - """ - self.acquire() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - """ - Release the lock. - - :param exc_type: the exception type if raised - :param exc_value: the exception value if raised - :param traceback: the exception traceback if raised - - """ - self.release() - - def __del__(self) -> None: - """Called when the lock object is deleted.""" - self.release(force=True) - - -__all__ = [ - "_UNSET_FILE_MODE", - "AcquireReturnProxy", - "BaseFileLock", -] diff --git a/venv/lib/python3.10/site-packages/filelock/_error.py b/venv/lib/python3.10/site-packages/filelock/_error.py deleted file mode 100644 index 7aaac6b005091938e4907fedb6889a00475c082e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/_error.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import annotations - -from typing import Any - - -class Timeout(TimeoutError): # noqa: N818 - """Raised when the lock could not be acquired in *timeout* seconds.""" - - def __init__(self, lock_file: str) -> None: - super().__init__() - self._lock_file = lock_file - - def __reduce__(self) -> str | tuple[Any, ...]: - return self.__class__, (self._lock_file,) # Properly pickle the exception - - def __str__(self) -> str: - return f"The file lock '{self._lock_file}' could not be acquired." - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.lock_file!r})" - - @property - def lock_file(self) -> str: - """:returns: The path of the file lock.""" - return self._lock_file - - -__all__ = [ - "Timeout", -] diff --git a/venv/lib/python3.10/site-packages/filelock/_read_write.py b/venv/lib/python3.10/site-packages/filelock/_read_write.py deleted file mode 100644 index bf9943332c1ff90ce66a4180a2b271dba85d72e1..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/_read_write.py +++ /dev/null @@ -1,363 +0,0 @@ -from __future__ import annotations - -import atexit -import logging -import os -import pathlib -import sqlite3 -import threading -import time -from contextlib import contextmanager, suppress -from typing import TYPE_CHECKING, Literal -from weakref import WeakValueDictionary - -from ._api import AcquireReturnProxy -from ._error import Timeout - -if TYPE_CHECKING: - from collections.abc import Generator - -_LOGGER = logging.getLogger("filelock") - -_all_connections: set[sqlite3.Connection] = set() -_all_connections_lock = threading.Lock() - - -def _cleanup_connections() -> None: - with _all_connections_lock: - for con in list(_all_connections): - with suppress(Exception): - con.close() - _all_connections.clear() - - -atexit.register(_cleanup_connections) - -# sqlite3_busy_timeout() accepts a C int, max 2_147_483_647 on 32-bit. Use a lower value to be safe (~23 days). -_MAX_SQLITE_TIMEOUT_MS = 2_000_000_000 - 1 - - -def timeout_for_sqlite(timeout: float, *, blocking: bool, already_waited: float) -> int: - if blocking is False: - return 0 - - if timeout == -1: - return _MAX_SQLITE_TIMEOUT_MS - - if timeout < 0: - msg = "timeout must be a non-negative number or -1" - raise ValueError(msg) - - remaining = max(timeout - already_waited, 0) if timeout > 0 else timeout - timeout_ms = int(remaining * 1000) - if timeout_ms > _MAX_SQLITE_TIMEOUT_MS or timeout_ms < 0: - _LOGGER.warning("timeout %s is too large for SQLite, using %s ms instead", timeout, _MAX_SQLITE_TIMEOUT_MS) - return _MAX_SQLITE_TIMEOUT_MS - return timeout_ms - - -class _ReadWriteLockMeta(type): - """ - Metaclass that handles singleton resolution when is_singleton=True. - - Singleton logic lives here rather than in ReadWriteLock.get_lock so that ``ReadWriteLock(path)`` transparently - returns cached instances without a 2-arg ``super()`` call that type checkers cannot verify. - - """ - - _instances: WeakValueDictionary[pathlib.Path, ReadWriteLock] - _instances_lock: threading.Lock - - def __call__( - cls, - lock_file: str | os.PathLike[str], - timeout: float = -1, - *, - blocking: bool = True, - is_singleton: bool = True, - ) -> ReadWriteLock: - if not is_singleton: - return super().__call__(lock_file, timeout, blocking=blocking, is_singleton=is_singleton) - - normalized = pathlib.Path(lock_file).resolve() - with cls._instances_lock: - if normalized not in cls._instances: - instance = super().__call__(lock_file, timeout, blocking=blocking, is_singleton=is_singleton) - cls._instances[normalized] = instance - else: - instance = cls._instances[normalized] - - if instance.timeout != timeout or instance.blocking != blocking: - msg = ( - f"Singleton lock created with timeout={instance.timeout}, blocking={instance.blocking}," - f" cannot be changed to timeout={timeout}, blocking={blocking}" - ) - raise ValueError(msg) - return instance - - -class ReadWriteLock(metaclass=_ReadWriteLockMeta): - """ - Cross-process read-write lock backed by SQLite. - - Allows concurrent shared readers or a single exclusive writer. The lock is reentrant within the same mode (multiple - ``acquire_read`` calls nest, as do multiple ``acquire_write`` calls from the same thread), but upgrading from read - to write or downgrading from write to read raises :class:`RuntimeError`. Write locks are pinned to the thread that - acquired them. - - By default, ``is_singleton=True``: calling ``ReadWriteLock(path)`` with the same resolved path returns the same - instance. The lock file must use a ``.db`` extension (SQLite database). - - :param lock_file: path to the SQLite database file used as the lock - :param timeout: maximum wait time in seconds; ``-1`` means block indefinitely - :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately when the lock is unavailable - :param is_singleton: if ``True``, reuse existing instances for the same resolved path - - .. versionadded:: 3.21.0 - - """ - - _instances: WeakValueDictionary[pathlib.Path, ReadWriteLock] = WeakValueDictionary() - _instances_lock = threading.Lock() - - @classmethod - def get_lock( - cls, lock_file: str | os.PathLike[str], timeout: float = -1, *, blocking: bool = True - ) -> ReadWriteLock: - """ - Return the singleton :class:`ReadWriteLock` for *lock_file*. - - :param lock_file: path to the SQLite database file used as the lock - :param timeout: maximum wait time in seconds; ``-1`` means block indefinitely - :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately when the lock is unavailable - - :returns: the singleton lock instance - - :raises ValueError: if an instance already exists for this path with different *timeout* or *blocking* values - - """ - return cls(lock_file, timeout, blocking=blocking) - - def __init__( - self, - lock_file: str | os.PathLike[str], - timeout: float = -1, - *, - blocking: bool = True, - is_singleton: bool = True, # noqa: ARG002 # consumed by _ReadWriteLockMeta.__call__ - ) -> None: - self.lock_file = os.fspath(lock_file) - self.timeout = timeout - self.blocking = blocking - self._transaction_lock = threading.Lock() # serializes the (possibly blocking) SQLite transaction work - self._internal_lock = threading.Lock() # protects _lock_level / _current_mode updates and rollback - self._lock_level = 0 - self._current_mode: Literal["read", "write"] | None = None - self._write_thread_id: int | None = None - self._con = sqlite3.connect(self.lock_file, check_same_thread=False) - with _all_connections_lock: - _all_connections.add(self._con) - - def _acquire_transaction_lock(self, *, blocking: bool, timeout: float) -> None: - if timeout == -1: - # blocking=True with no timeout means wait indefinitely per threading.Lock.acquire semantics - acquired = self._transaction_lock.acquire(blocking) - else: - acquired = self._transaction_lock.acquire(blocking, timeout) - if not acquired: - raise Timeout(self.lock_file) from None - - def _validate_reentrant(self, mode: Literal["read", "write"], opposite: str, direction: str) -> AcquireReturnProxy: - if self._current_mode != mode: - msg = ( - f"Cannot acquire {mode} lock on {self.lock_file} (lock id: {id(self)}): " - f"already holding a {opposite} lock ({direction} not allowed)" - ) - raise RuntimeError(msg) - if mode == "write" and (cur := threading.get_ident()) != self._write_thread_id: - msg = ( - f"Cannot acquire write lock on {self.lock_file} (lock id: {id(self)}) " - f"from thread {cur} while it is held by thread {self._write_thread_id}" - ) - raise RuntimeError(msg) - self._lock_level += 1 - return AcquireReturnProxy(lock=self) - - def _configure_and_begin( - self, mode: Literal["read", "write"], timeout: float, *, blocking: bool, start_time: float - ) -> None: - waited = time.perf_counter() - start_time - timeout_ms = timeout_for_sqlite(timeout, blocking=blocking, already_waited=waited) - self._con.execute(f"PRAGMA busy_timeout={timeout_ms};").close() - # Use legacy journal mode (not WAL) because WAL does not block readers when a concurrent EXCLUSIVE - # write transaction is active, making read-write locking impossible without modifying table data. - # MEMORY is safe here since no actual writes happen — crashes cannot corrupt the DB. - # See https://sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions - # - # Set here (not in __init__) because this pragma itself may block on a locked database, - # so it must run after busy_timeout is configured above. - self._con.execute("PRAGMA journal_mode=MEMORY;").close() - # Recompute remaining timeout after the potentially blocking journal_mode pragma. - waited = time.perf_counter() - start_time - if (recomputed := timeout_for_sqlite(timeout, blocking=blocking, already_waited=waited)) != timeout_ms: - self._con.execute(f"PRAGMA busy_timeout={recomputed};").close() - stmt = "BEGIN EXCLUSIVE TRANSACTION;" if mode == "write" else "BEGIN TRANSACTION;" - self._con.execute(stmt).close() - if mode == "read": - # A SELECT is needed to force SQLite to actually acquire the SHARED lock on the database. - # https://www.sqlite.org/lockingv3.html#transaction_control - self._con.execute("SELECT name FROM sqlite_schema LIMIT 1;").close() - - def _acquire(self, mode: Literal["read", "write"], timeout: float, *, blocking: bool) -> AcquireReturnProxy: - opposite = "write" if mode == "read" else "read" - direction = "downgrade" if mode == "read" else "upgrade" - - with self._internal_lock: - if self._lock_level > 0: - return self._validate_reentrant(mode, opposite, direction) - - start_time = time.perf_counter() - self._acquire_transaction_lock(blocking=blocking, timeout=timeout) - try: - # Double-check: another thread may have acquired the lock while we waited on _transaction_lock. - with self._internal_lock: - if self._lock_level > 0: - return self._validate_reentrant(mode, opposite, direction) - - self._configure_and_begin(mode, timeout, blocking=blocking, start_time=start_time) - - with self._internal_lock: - self._current_mode = mode - self._lock_level = 1 - if mode == "write": - self._write_thread_id = threading.get_ident() - - return AcquireReturnProxy(lock=self) - - except sqlite3.OperationalError as exc: - if "database is locked" not in str(exc): - raise - raise Timeout(self.lock_file) from None - finally: - self._transaction_lock.release() - - def acquire_read(self, timeout: float = -1, *, blocking: bool = True) -> AcquireReturnProxy: - """ - Acquire a shared read lock. - - If this instance already holds a read lock, the lock level is incremented (reentrant). Attempting to acquire a - read lock while holding a write lock raises :class:`RuntimeError` (downgrade not allowed). - - :param timeout: maximum wait time in seconds; ``-1`` means block indefinitely - :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately when the lock is unavailable - - :returns: a proxy that can be used as a context manager to release the lock - - :raises RuntimeError: if a write lock is already held on this instance - :raises Timeout: if the lock cannot be acquired within *timeout* seconds - - """ - return self._acquire("read", timeout, blocking=blocking) - - def acquire_write(self, timeout: float = -1, *, blocking: bool = True) -> AcquireReturnProxy: - """ - Acquire an exclusive write lock. - - If this instance already holds a write lock from the same thread, the lock level is incremented (reentrant). - Attempting to acquire a write lock while holding a read lock raises :class:`RuntimeError` (upgrade not allowed). - Write locks are pinned to the acquiring thread: a different thread trying to re-enter also raises - :class:`RuntimeError`. - - :param timeout: maximum wait time in seconds; ``-1`` means block indefinitely - :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately when the lock is unavailable - - :returns: a proxy that can be used as a context manager to release the lock - - :raises RuntimeError: if a read lock is already held, or a write lock is held by a different thread - :raises Timeout: if the lock cannot be acquired within *timeout* seconds - - """ - return self._acquire("write", timeout, blocking=blocking) - - def release(self, *, force: bool = False) -> None: - """ - Release one level of the current lock. - - When the lock level reaches zero the underlying SQLite transaction is rolled back, releasing the database lock. - - :param force: if ``True``, release the lock completely regardless of the current lock level - - :raises RuntimeError: if no lock is currently held and *force* is ``False`` - - """ - should_rollback = False - with self._internal_lock: - if self._lock_level == 0: - if force: - return - msg = f"Cannot release a lock on {self.lock_file} (lock id: {id(self)}) that is not held" - raise RuntimeError(msg) - if force: - self._lock_level = 0 - else: - self._lock_level -= 1 - if self._lock_level == 0: - self._current_mode = None - self._write_thread_id = None - should_rollback = True - if should_rollback: - self._con.rollback() - - @contextmanager - def read_lock(self, timeout: float | None = None, *, blocking: bool | None = None) -> Generator[None]: - """ - Context manager that acquires and releases a shared read lock. - - Falls back to instance defaults for *timeout* and *blocking* when ``None``. - - :param timeout: maximum wait time in seconds, or ``None`` to use the instance default - :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately; ``None`` uses the instance default - - """ - if timeout is None: - timeout = self.timeout - if blocking is None: - blocking = self.blocking - self.acquire_read(timeout, blocking=blocking) - try: - yield - finally: - self.release() - - @contextmanager - def write_lock(self, timeout: float | None = None, *, blocking: bool | None = None) -> Generator[None]: - """ - Context manager that acquires and releases an exclusive write lock. - - Falls back to instance defaults for *timeout* and *blocking* when ``None``. - - :param timeout: maximum wait time in seconds, or ``None`` to use the instance default - :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately; ``None`` uses the instance default - - """ - if timeout is None: - timeout = self.timeout - if blocking is None: - blocking = self.blocking - self.acquire_write(timeout, blocking=blocking) - try: - yield - finally: - self.release() - - def close(self) -> None: - """ - Release the lock (if held) and close the underlying SQLite connection. - - After calling this method, the lock instance is no longer usable. - - """ - self.release(force=True) - self._con.close() - with _all_connections_lock: - _all_connections.discard(self._con) diff --git a/venv/lib/python3.10/site-packages/filelock/_soft.py b/venv/lib/python3.10/site-packages/filelock/_soft.py deleted file mode 100644 index 3bec57aafd38a2d659ba46bab06fa8d045c35af2..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/_soft.py +++ /dev/null @@ -1,127 +0,0 @@ -from __future__ import annotations - -import os -import socket -import sys -import time -from contextlib import suppress -from errno import EACCES, EEXIST, EPERM, ESRCH -from pathlib import Path - -from ._api import BaseFileLock -from ._util import ensure_directory_exists, raise_on_not_writable_file - -_WIN_SYNCHRONIZE = 0x100000 -_WIN_ERROR_INVALID_PARAMETER = 87 - - -class SoftFileLock(BaseFileLock): - """ - Portable file lock based on file existence. - - Unlike :class:`UnixFileLock ` and :class:`WindowsFileLock `, this - lock does not use OS-level locking primitives. Instead, it creates the lock file with ``O_CREAT | O_EXCL`` and - treats its existence as the lock indicator. This makes it work on any filesystem but leaves stale lock files behind - if the process crashes without releasing the lock. - - To mitigate stale locks, the lock file contains the PID and hostname of the holding process. On contention, if the - holder is on the same host and its PID no longer exists, the stale lock is broken automatically. - - """ - - def _acquire(self) -> None: - raise_on_not_writable_file(self.lock_file) - ensure_directory_exists(self.lock_file) - flags = ( - os.O_WRONLY # open for writing only - | os.O_CREAT - | os.O_EXCL # together with above raise EEXIST if the file specified by filename exists - | os.O_TRUNC # truncate the file to zero byte - ) - if (o_nofollow := getattr(os, "O_NOFOLLOW", None)) is not None: - flags |= o_nofollow - try: - file_handler = os.open(self.lock_file, flags, self._open_mode()) - except OSError as exception: - if not ( - exception.errno == EEXIST or (exception.errno == EACCES and sys.platform == "win32") - ): # pragma: win32 no cover - raise - if exception.errno == EEXIST and sys.platform != "win32": # pragma: win32 no cover - self._try_break_stale_lock() - else: - self._write_lock_info(file_handler) - self._context.lock_file_fd = file_handler - - def _try_break_stale_lock(self) -> None: - with suppress(OSError): - content = Path(self.lock_file).read_text(encoding="utf-8") - lines = content.strip().splitlines() - if len(lines) != 2: # noqa: PLR2004 - return - pid_str, hostname = lines - if hostname != socket.gethostname(): - return - pid = int(pid_str) - if self._is_process_alive(pid): - return - break_path = f"{self.lock_file}.break.{os.getpid()}" - Path(self.lock_file).rename(break_path) - Path(break_path).unlink() - - @staticmethod - def _is_process_alive(pid: int) -> bool: - if sys.platform == "win32": # pragma: win32 cover - import ctypes # noqa: PLC0415 - - kernel32 = ctypes.windll.kernel32 - handle = kernel32.OpenProcess(_WIN_SYNCHRONIZE, 0, pid) - if handle: - kernel32.CloseHandle(handle) - return True - return kernel32.GetLastError() != _WIN_ERROR_INVALID_PARAMETER - try: - os.kill(pid, 0) - except OSError as exc: - if exc.errno == ESRCH: - return False - if exc.errno == EPERM: - return True - raise - return True - - @staticmethod - def _write_lock_info(fd: int) -> None: - with suppress(OSError): - os.write(fd, f"{os.getpid()}\n{socket.gethostname()}\n".encode()) - - def _release(self) -> None: - assert self._context.lock_file_fd is not None # noqa: S101 - os.close(self._context.lock_file_fd) - self._context.lock_file_fd = None - if sys.platform == "win32": - self._windows_unlink_with_retry() - else: - with suppress(OSError): - Path(self.lock_file).unlink() - - def _windows_unlink_with_retry(self) -> None: - max_retries = 10 - retry_delay = 0.001 - for attempt in range(max_retries): - # Windows doesn't immediately release file handles after close, causing EACCES/EPERM on unlink - try: - Path(self.lock_file).unlink() - except OSError as exc: # noqa: PERF203 - if exc.errno not in {EACCES, EPERM}: - return - if attempt < max_retries - 1: - time.sleep(retry_delay) - retry_delay *= 2 - else: - return - - -__all__ = [ - "SoftFileLock", -] diff --git a/venv/lib/python3.10/site-packages/filelock/_unix.py b/venv/lib/python3.10/site-packages/filelock/_unix.py deleted file mode 100644 index 7f8e8b007fd8d3488ebfb3b7a7f7a20921837e9e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/_unix.py +++ /dev/null @@ -1,109 +0,0 @@ -from __future__ import annotations - -import os -import sys -import warnings -from contextlib import suppress -from errno import EAGAIN, ENOSYS, EWOULDBLOCK -from pathlib import Path -from typing import cast - -from ._api import BaseFileLock -from ._util import ensure_directory_exists - -#: a flag to indicate if the fcntl API is available -has_fcntl = False -if sys.platform == "win32": # pragma: win32 cover - - class UnixFileLock(BaseFileLock): - """Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems.""" - - def _acquire(self) -> None: - raise NotImplementedError - - def _release(self) -> None: - raise NotImplementedError - -else: # pragma: win32 no cover - try: - import fcntl - - _ = (fcntl.flock, fcntl.LOCK_EX, fcntl.LOCK_NB, fcntl.LOCK_UN) - except (ImportError, AttributeError): - pass - else: - has_fcntl = True - - class UnixFileLock(BaseFileLock): - """Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems.""" - - def _acquire(self) -> None: # noqa: C901, PLR0912 - ensure_directory_exists(self.lock_file) - open_flags = os.O_RDWR | os.O_TRUNC - o_nofollow = getattr(os, "O_NOFOLLOW", None) - if o_nofollow is not None: - open_flags |= o_nofollow - open_flags |= os.O_CREAT - open_mode = self._open_mode() - try: - fd = os.open(self.lock_file, open_flags, open_mode) - except FileNotFoundError: - # On FUSE/NFS, os.open(O_CREAT) is not atomic: LOOKUP + CREATE can be split, allowing a concurrent - # unlink() to delete the file between them. For valid paths, treat ENOENT as transient contention. - # For invalid paths (e.g., empty string), re-raise to avoid infinite retry loops. - if self.lock_file and Path(self.lock_file).parent.exists(): - return - raise - except PermissionError: - # Sticky-bit dirs (e.g. /tmp): O_CREAT fails if the file is owned by another user (#317). - # Fall back to opening the existing file without O_CREAT. - if not Path(self.lock_file).exists(): - raise - try: - fd = os.open(self.lock_file, open_flags & ~os.O_CREAT, open_mode) - except FileNotFoundError: - return - if self.has_explicit_mode: - with suppress(PermissionError): - os.fchmod(fd, self._context.mode) - try: - fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) - except OSError as exception: - os.close(fd) - if exception.errno == ENOSYS: - with suppress(OSError): - Path(self.lock_file).unlink() - self._fallback_to_soft_lock() - self._acquire() - return - if exception.errno not in {EAGAIN, EWOULDBLOCK}: - raise - else: - # The file may have been unlinked by a concurrent _release() between our open() and flock(). - # A lock on an unlinked inode is useless — discard and let the retry loop start fresh. - if os.fstat(fd).st_nlink == 0: - os.close(fd) - else: - self._context.lock_file_fd = fd - - def _fallback_to_soft_lock(self) -> None: - from ._soft import SoftFileLock # noqa: PLC0415 - - warnings.warn("flock not supported on this filesystem, falling back to SoftFileLock", stacklevel=2) - from .asyncio import AsyncSoftFileLock, BaseAsyncFileLock # noqa: PLC0415 - - self.__class__ = AsyncSoftFileLock if isinstance(self, BaseAsyncFileLock) else SoftFileLock - - def _release(self) -> None: - fd = cast("int", self._context.lock_file_fd) - self._context.lock_file_fd = None - with suppress(OSError): - Path(self.lock_file).unlink() - fcntl.flock(fd, fcntl.LOCK_UN) - os.close(fd) - - -__all__ = [ - "UnixFileLock", - "has_fcntl", -] diff --git a/venv/lib/python3.10/site-packages/filelock/_util.py b/venv/lib/python3.10/site-packages/filelock/_util.py deleted file mode 100644 index 670152393ed76d2cecf4cf5e774360af4380f319..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/_util.py +++ /dev/null @@ -1,53 +0,0 @@ -from __future__ import annotations - -import os -import stat -import sys -from errno import EACCES, EISDIR -from pathlib import Path - - -def raise_on_not_writable_file(filename: str) -> None: - """ - Raise an exception if attempting to open the file for writing would fail. - - This is done so files that will never be writable can be separated from files that are writable but currently - locked. - - :param filename: file to check - - :raises OSError: as if the file was opened for writing. - - """ - try: # use stat to do exists + can write to check without race condition - file_stat = os.stat(filename) # noqa: PTH116 - except OSError: - return # swallow does not exist or other errors - - if file_stat.st_mtime != 0: # if os.stat returns but modification is zero that's an invalid os.stat - ignore it - if not (file_stat.st_mode & stat.S_IWUSR): - raise PermissionError(EACCES, "Permission denied", filename) - - if stat.S_ISDIR(file_stat.st_mode): - if sys.platform == "win32": # pragma: win32 cover - # On Windows, this is PermissionError - raise PermissionError(EACCES, "Permission denied", filename) - else: # pragma: win32 no cover # noqa: RET506 - # On linux / macOS, this is IsADirectoryError - raise IsADirectoryError(EISDIR, "Is a directory", filename) - - -def ensure_directory_exists(filename: Path | str) -> None: - """ - Ensure the directory containing the file exists (create it if necessary). - - :param filename: file. - - """ - Path(filename).parent.mkdir(parents=True, exist_ok=True) - - -__all__ = [ - "ensure_directory_exists", - "raise_on_not_writable_file", -] diff --git a/venv/lib/python3.10/site-packages/filelock/_windows.py b/venv/lib/python3.10/site-packages/filelock/_windows.py deleted file mode 100644 index 23bff364a6fa025458d7188861a6e1a7677606f1..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/_windows.py +++ /dev/null @@ -1,100 +0,0 @@ -from __future__ import annotations - -import os -import sys -from errno import EACCES -from typing import cast - -from ._api import BaseFileLock -from ._util import ensure_directory_exists, raise_on_not_writable_file - -if sys.platform == "win32": # pragma: win32 cover - import ctypes - import msvcrt - from ctypes import wintypes - - # Windows API constants for reparse point detection - FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 - INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF - - # Load kernel32.dll - _kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) - _kernel32.GetFileAttributesW.argtypes = [wintypes.LPCWSTR] - _kernel32.GetFileAttributesW.restype = wintypes.DWORD - - def _is_reparse_point(path: str) -> bool: - """ - Check if a path is a reparse point (symlink, junction, etc.) on Windows. - - :param path: Path to check - - :returns: True if path is a reparse point, False otherwise - - :raises OSError: If GetFileAttributesW fails for reasons other than file-not-found - - """ - attrs = _kernel32.GetFileAttributesW(path) - if attrs == INVALID_FILE_ATTRIBUTES: - # File doesn't exist yet - that's fine, we'll create it - err = ctypes.get_last_error() - if err == 2: # noqa: PLR2004 # ERROR_FILE_NOT_FOUND - return False - if err == 3: # noqa: PLR2004 # ERROR_PATH_NOT_FOUND - return False - # Some other error - let caller handle it - return False - return bool(attrs & FILE_ATTRIBUTE_REPARSE_POINT) - - class WindowsFileLock(BaseFileLock): - """Uses the :func:`msvcrt.locking` function to hard lock the lock file on Windows systems.""" - - def _acquire(self) -> None: - raise_on_not_writable_file(self.lock_file) - ensure_directory_exists(self.lock_file) - - # Security check: Refuse to open reparse points (symlinks, junctions) - # This prevents TOCTOU symlink attacks (CVE-TBD) - if _is_reparse_point(self.lock_file): - msg = f"Lock file is a reparse point (symlink/junction): {self.lock_file}" - raise OSError(msg) - - flags = ( - os.O_RDWR # open for read and write - | os.O_CREAT # create file if not exists - ) - try: - fd = os.open(self.lock_file, flags, self._open_mode()) - except OSError as exception: - if exception.errno != EACCES: # has no access to this lock - raise - else: - try: - msvcrt.locking(fd, msvcrt.LK_NBLCK, 1) - except OSError as exception: - os.close(fd) # close file first - if exception.errno != EACCES: # file is already locked - raise - else: - self._context.lock_file_fd = fd - - def _release(self) -> None: - fd = cast("int", self._context.lock_file_fd) - self._context.lock_file_fd = None - msvcrt.locking(fd, msvcrt.LK_UNLCK, 1) - os.close(fd) - -else: # pragma: win32 no cover - - class WindowsFileLock(BaseFileLock): - """Uses the :func:`msvcrt.locking` function to hard lock the lock file on Windows systems.""" - - def _acquire(self) -> None: - raise NotImplementedError - - def _release(self) -> None: - raise NotImplementedError - - -__all__ = [ - "WindowsFileLock", -] diff --git a/venv/lib/python3.10/site-packages/filelock/asyncio.py b/venv/lib/python3.10/site-packages/filelock/asyncio.py deleted file mode 100644 index 81743adff7e9684ff3d3ce6c23a0220bc95e7a68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/asyncio.py +++ /dev/null @@ -1,376 +0,0 @@ -"""An asyncio-based implementation of the file lock.""" - -from __future__ import annotations - -import asyncio -import contextlib -import logging -import os -import time -from dataclasses import dataclass -from inspect import iscoroutinefunction -from threading import local -from typing import TYPE_CHECKING, Any, NoReturn, cast - -from ._api import _UNSET_FILE_MODE, BaseFileLock, FileLockContext, FileLockMeta -from ._error import Timeout -from ._soft import SoftFileLock -from ._unix import UnixFileLock -from ._windows import WindowsFileLock - -if TYPE_CHECKING: - import sys - from collections.abc import Callable - from concurrent import futures - from types import TracebackType - - if sys.version_info >= (3, 11): # pragma: no cover (py311+) - from typing import Self - else: # pragma: no cover ( None: # noqa: D107 - self.lock = lock - - async def __aenter__(self) -> BaseAsyncFileLock: # noqa: D105 - return self.lock - - async def __aexit__( # noqa: D105 - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - await self.lock.release() - - -class AsyncFileLockMeta(FileLockMeta): - def __call__( # ty: ignore[invalid-method-override] # noqa: PLR0913 - cls, # noqa: N805 - lock_file: str | os.PathLike[str], - timeout: float = -1, - mode: int = _UNSET_FILE_MODE, - thread_local: bool = False, # noqa: FBT001, FBT002 - *, - blocking: bool = True, - is_singleton: bool = False, - poll_interval: float = 0.05, - lifetime: float | None = None, - loop: asyncio.AbstractEventLoop | None = None, - run_in_executor: bool = True, - executor: futures.Executor | None = None, - ) -> BaseAsyncFileLock: - if thread_local and run_in_executor: - msg = "run_in_executor is not supported when thread_local is True" - raise ValueError(msg) - instance = super().__call__( - lock_file=lock_file, - timeout=timeout, - mode=mode, - thread_local=thread_local, - blocking=blocking, - is_singleton=is_singleton, - poll_interval=poll_interval, - lifetime=lifetime, - loop=loop, - run_in_executor=run_in_executor, - executor=executor, - ) - return cast("BaseAsyncFileLock", instance) - - -class BaseAsyncFileLock(BaseFileLock, metaclass=AsyncFileLockMeta): - """ - Base class for asynchronous file locks. - - .. versionadded:: 3.15.0 - - """ - - def __init__( # noqa: PLR0913 - self, - lock_file: str | os.PathLike[str], - timeout: float = -1, - mode: int = _UNSET_FILE_MODE, - thread_local: bool = False, # noqa: FBT001, FBT002 - *, - blocking: bool = True, - is_singleton: bool = False, - poll_interval: float = 0.05, - lifetime: float | None = None, - loop: asyncio.AbstractEventLoop | None = None, - run_in_executor: bool = True, - executor: futures.Executor | None = None, - ) -> None: - """ - Create a new lock object. - - :param lock_file: path to the file - :param timeout: default timeout when acquiring the lock, in seconds. It will be used as fallback value in the - acquire method, if no timeout value (``None``) is given. If you want to disable the timeout, set it to a - negative value. A timeout of 0 means that there is exactly one attempt to acquire the file lock. - :param mode: file permissions for the lockfile. When not specified, the OS controls permissions via umask and - default ACLs, preserving POSIX default ACL inheritance in shared directories. - :param thread_local: Whether this object's internal context should be thread local or not. If this is set to - ``False`` then the lock will be reentrant across threads. - :param blocking: whether the lock should be blocking or not - :param is_singleton: If this is set to ``True`` then only one instance of this class will be created per lock - file. This is useful if you want to use the lock object for reentrant locking without needing to pass the - same object around. - :param poll_interval: default interval for polling the lock file, in seconds. It will be used as fallback value - in the acquire method, if no poll_interval value (``None``) is given. - :param lifetime: maximum time in seconds a lock can be held before it is considered expired. When set, a waiting - process will break a lock whose file modification time is older than ``lifetime`` seconds. ``None`` (the - default) means locks never expire. - :param loop: The event loop to use. If not specified, the running event loop will be used. - :param run_in_executor: If this is set to ``True`` then the lock will be acquired in an executor. - :param executor: The executor to use. If not specified, the default executor will be used. - - """ - self._is_thread_local = thread_local - self._is_singleton = is_singleton - - # Create the context. Note that external code should not work with the context directly and should instead use - # properties of this class. - kwargs: dict[str, Any] = { - "lock_file": os.fspath(lock_file), - "timeout": timeout, - "mode": mode, - "blocking": blocking, - "poll_interval": poll_interval, - "lifetime": lifetime, - "loop": loop, - "run_in_executor": run_in_executor, - "executor": executor, - } - self._context: AsyncFileLockContext = (AsyncThreadLocalFileContext if thread_local else AsyncFileLockContext)( - **kwargs - ) - - @property - def run_in_executor(self) -> bool: - """:returns: whether run in executor.""" - return self._context.run_in_executor - - @property - def executor(self) -> futures.Executor | None: - """:returns: the executor.""" - return self._context.executor - - @executor.setter - def executor(self, value: futures.Executor | None) -> None: # pragma: no cover - """ - Change the executor. - - :param futures.Executor | None value: the new executor or ``None`` - - """ - self._context.executor = value - - @property - def loop(self) -> asyncio.AbstractEventLoop | None: - """:returns: the event loop.""" - return self._context.loop - - async def acquire( # ty: ignore[invalid-method-override] - self, - timeout: float | None = None, - poll_interval: float | None = None, - *, - blocking: bool | None = None, - cancel_check: Callable[[], bool] | None = None, - ) -> AsyncAcquireReturnProxy: - """ - Try to acquire the file lock. - - :param timeout: maximum wait time for acquiring the lock, ``None`` means use the default - :attr:`~BaseFileLock.timeout` is and if ``timeout < 0``, there is no timeout and this method will block - until the lock could be acquired - :param poll_interval: interval of trying to acquire the lock file, ``None`` means use the default - :attr:`~BaseFileLock.poll_interval` - :param blocking: defaults to True. If False, function will return immediately if it cannot obtain a lock on the - first attempt. Otherwise, this method will block until the timeout expires or the lock is acquired. - :param cancel_check: a callable returning ``True`` when the acquisition should be canceled. Checked on each poll - iteration. When triggered, raises :class:`~Timeout` just like an expired timeout. - - :returns: a context object that will unlock the file when the context is exited - - :raises Timeout: if fails to acquire lock within the timeout period - - .. code-block:: python - - # You can use this method in the context manager (recommended) - with lock.acquire(): - pass - - # Or use an equivalent try-finally construct: - lock.acquire() - try: - pass - finally: - lock.release() - - """ - # Use the default timeout, if no timeout is provided. - if timeout is None: - timeout = self._context.timeout - - if blocking is None: - blocking = self._context.blocking - - if poll_interval is None: - poll_interval = self._context.poll_interval - - # Increment the number right at the beginning. We can still undo it, if something fails. - self._context.lock_counter += 1 - - lock_id = id(self) - lock_filename = self.lock_file - start_time = time.perf_counter() - try: - while True: - if not self.is_locked: - self._try_break_expired_lock() - _LOGGER.debug("Attempting to acquire lock %s on %s", lock_id, lock_filename) - await self._run_internal_method(self._acquire) - if self.is_locked: - _LOGGER.debug("Lock %s acquired on %s", lock_id, lock_filename) - break - if self._check_give_up( - lock_id, - lock_filename, - blocking=blocking, - cancel_check=cancel_check, - timeout=timeout, - start_time=start_time, - ): - raise Timeout(lock_filename) # noqa: TRY301 - msg = "Lock %s not acquired on %s, waiting %s seconds ..." - _LOGGER.debug(msg, lock_id, lock_filename, poll_interval) - await asyncio.sleep(poll_interval) - except BaseException: # Something did go wrong, so decrement the counter. - self._context.lock_counter = max(0, self._context.lock_counter - 1) - raise - return AsyncAcquireReturnProxy(lock=self) - - async def release(self, force: bool = False) -> None: # ty: ignore[invalid-method-override] # noqa: FBT001, FBT002 - """ - Release the file lock. The lock is only completely released when the lock counter reaches 0. The lock file - itself is not automatically deleted. - - :param force: If true, the lock counter is ignored and the lock is released in every case. - - """ - if self.is_locked: - self._context.lock_counter -= 1 - - if self._context.lock_counter == 0 or force: - lock_id, lock_filename = id(self), self.lock_file - - _LOGGER.debug("Attempting to release lock %s on %s", lock_id, lock_filename) - await self._run_internal_method(self._release) - self._context.lock_counter = 0 - _LOGGER.debug("Lock %s released on %s", lock_id, lock_filename) - - async def _run_internal_method(self, method: Callable[[], Any]) -> None: - if iscoroutinefunction(method): - await method() - elif self.run_in_executor: - loop = self.loop or asyncio.get_running_loop() - await loop.run_in_executor(self.executor, method) - else: - method() - - def __enter__(self) -> NoReturn: - """ - Replace old __enter__ method to avoid using it. - - NOTE: DO NOT USE `with` FOR ASYNCIO LOCKS, USE `async with` INSTEAD. - - :returns: none - :rtype: NoReturn - - """ - msg = "Do not use `with` for asyncio locks, use `async with` instead." - raise NotImplementedError(msg) - - async def __aenter__(self) -> Self: - """ - Acquire the lock. - - :returns: the lock object - - """ - await self.acquire() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - """ - Release the lock. - - :param exc_type: the exception type if raised - :param exc_value: the exception value if raised - :param traceback: the exception traceback if raised - - """ - await self.release() - - def __del__(self) -> None: - """Called when the lock object is deleted.""" - with contextlib.suppress(RuntimeError): - loop = self.loop or asyncio.get_running_loop() - if not loop.is_running(): # pragma: no cover - loop.run_until_complete(self.release(force=True)) - else: - loop.create_task(self.release(force=True)) - - -class AsyncSoftFileLock(SoftFileLock, BaseAsyncFileLock): - """Simply watches the existence of the lock file.""" - - -class AsyncUnixFileLock(UnixFileLock, BaseAsyncFileLock): - """Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems.""" - - -class AsyncWindowsFileLock(WindowsFileLock, BaseAsyncFileLock): - """Uses the :func:`msvcrt.locking` to hard lock the lock file on windows systems.""" - - -__all__ = [ - "AsyncAcquireReturnProxy", - "AsyncSoftFileLock", - "AsyncUnixFileLock", - "AsyncWindowsFileLock", - "BaseAsyncFileLock", -] diff --git a/venv/lib/python3.10/site-packages/filelock/py.typed b/venv/lib/python3.10/site-packages/filelock/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/filelock/version.py b/venv/lib/python3.10/site-packages/filelock/version.py deleted file mode 100644 index 9702f54520ecd2906c28c83c9a17bb3bb87d7ecd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/filelock/version.py +++ /dev/null @@ -1,34 +0,0 @@ -# file generated by setuptools-scm -# don't change, don't track in version control - -__all__ = [ - "__version__", - "__version_tuple__", - "version", - "version_tuple", - "__commit_id__", - "commit_id", -] - -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import Tuple - from typing import Union - - VERSION_TUPLE = Tuple[Union[int, str], ...] - COMMIT_ID = Union[str, None] -else: - VERSION_TUPLE = object - COMMIT_ID = object - -version: str -__version__: str -__version_tuple__: VERSION_TUPLE -version_tuple: VERSION_TUPLE -commit_id: COMMIT_ID -__commit_id__: COMMIT_ID - -__version__ = version = '3.24.3' -__version_tuple__ = version_tuple = (3, 24, 3) - -__commit_id__ = commit_id = None diff --git a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/METADATA b/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/METADATA deleted file mode 100644 index bb96eb3cf23a281f3ea8c7e1fe1c8a2a1fcaa2f5..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/METADATA +++ /dev/null @@ -1,257 +0,0 @@ -Metadata-Version: 2.4 -Name: fsspec -Version: 2026.2.0 -Summary: File-system specification -Project-URL: Changelog, https://filesystem-spec.readthedocs.io/en/latest/changelog.html -Project-URL: Documentation, https://filesystem-spec.readthedocs.io/en/latest/ -Project-URL: Homepage, https://github.com/fsspec/filesystem_spec -Maintainer-email: Martin Durant -License-Expression: BSD-3-Clause -License-File: LICENSE -Keywords: file -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Requires-Python: >=3.10 -Provides-Extra: abfs -Requires-Dist: adlfs; extra == 'abfs' -Provides-Extra: adl -Requires-Dist: adlfs; extra == 'adl' -Provides-Extra: arrow -Requires-Dist: pyarrow>=1; extra == 'arrow' -Provides-Extra: dask -Requires-Dist: dask; extra == 'dask' -Requires-Dist: distributed; extra == 'dask' -Provides-Extra: dev -Requires-Dist: pre-commit; extra == 'dev' -Requires-Dist: ruff>=0.5; extra == 'dev' -Provides-Extra: doc -Requires-Dist: numpydoc; extra == 'doc' -Requires-Dist: sphinx; extra == 'doc' -Requires-Dist: sphinx-design; extra == 'doc' -Requires-Dist: sphinx-rtd-theme; extra == 'doc' -Requires-Dist: yarl; extra == 'doc' -Provides-Extra: dropbox -Requires-Dist: dropbox; extra == 'dropbox' -Requires-Dist: dropboxdrivefs; extra == 'dropbox' -Requires-Dist: requests; extra == 'dropbox' -Provides-Extra: entrypoints -Provides-Extra: full -Requires-Dist: adlfs; extra == 'full' -Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'full' -Requires-Dist: dask; extra == 'full' -Requires-Dist: distributed; extra == 'full' -Requires-Dist: dropbox; extra == 'full' -Requires-Dist: dropboxdrivefs; extra == 'full' -Requires-Dist: fusepy; extra == 'full' -Requires-Dist: gcsfs>2024.2.0; extra == 'full' -Requires-Dist: libarchive-c; extra == 'full' -Requires-Dist: ocifs; extra == 'full' -Requires-Dist: panel; extra == 'full' -Requires-Dist: paramiko; extra == 'full' -Requires-Dist: pyarrow>=1; extra == 'full' -Requires-Dist: pygit2; extra == 'full' -Requires-Dist: requests; extra == 'full' -Requires-Dist: s3fs>2024.2.0; extra == 'full' -Requires-Dist: smbprotocol; extra == 'full' -Requires-Dist: tqdm; extra == 'full' -Provides-Extra: fuse -Requires-Dist: fusepy; extra == 'fuse' -Provides-Extra: gcs -Requires-Dist: gcsfs>2024.2.0; extra == 'gcs' -Provides-Extra: git -Requires-Dist: pygit2; extra == 'git' -Provides-Extra: github -Requires-Dist: requests; extra == 'github' -Provides-Extra: gs -Requires-Dist: gcsfs; extra == 'gs' -Provides-Extra: gui -Requires-Dist: panel; extra == 'gui' -Provides-Extra: hdfs -Requires-Dist: pyarrow>=1; extra == 'hdfs' -Provides-Extra: http -Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'http' -Provides-Extra: libarchive -Requires-Dist: libarchive-c; extra == 'libarchive' -Provides-Extra: oci -Requires-Dist: ocifs; extra == 'oci' -Provides-Extra: s3 -Requires-Dist: s3fs>2024.2.0; extra == 's3' -Provides-Extra: sftp -Requires-Dist: paramiko; extra == 'sftp' -Provides-Extra: smb -Requires-Dist: smbprotocol; extra == 'smb' -Provides-Extra: ssh -Requires-Dist: paramiko; extra == 'ssh' -Provides-Extra: test -Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test' -Requires-Dist: numpy; extra == 'test' -Requires-Dist: pytest; extra == 'test' -Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test' -Requires-Dist: pytest-benchmark; extra == 'test' -Requires-Dist: pytest-cov; extra == 'test' -Requires-Dist: pytest-mock; extra == 'test' -Requires-Dist: pytest-recording; extra == 'test' -Requires-Dist: pytest-rerunfailures; extra == 'test' -Requires-Dist: requests; extra == 'test' -Provides-Extra: test-downstream -Requires-Dist: aiobotocore<3.0.0,>=2.5.4; extra == 'test-downstream' -Requires-Dist: dask[dataframe,test]; extra == 'test-downstream' -Requires-Dist: moto[server]<5,>4; extra == 'test-downstream' -Requires-Dist: pytest-timeout; extra == 'test-downstream' -Requires-Dist: xarray; extra == 'test-downstream' -Provides-Extra: test-full -Requires-Dist: adlfs; extra == 'test-full' -Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test-full' -Requires-Dist: backports-zstd; (python_version < '3.14') and extra == 'test-full' -Requires-Dist: cloudpickle; extra == 'test-full' -Requires-Dist: dask; extra == 'test-full' -Requires-Dist: distributed; extra == 'test-full' -Requires-Dist: dropbox; extra == 'test-full' -Requires-Dist: dropboxdrivefs; extra == 'test-full' -Requires-Dist: fastparquet; extra == 'test-full' -Requires-Dist: fusepy; extra == 'test-full' -Requires-Dist: gcsfs; extra == 'test-full' -Requires-Dist: jinja2; extra == 'test-full' -Requires-Dist: kerchunk; extra == 'test-full' -Requires-Dist: libarchive-c; extra == 'test-full' -Requires-Dist: lz4; extra == 'test-full' -Requires-Dist: notebook; extra == 'test-full' -Requires-Dist: numpy; extra == 'test-full' -Requires-Dist: ocifs; extra == 'test-full' -Requires-Dist: pandas<3.0.0; extra == 'test-full' -Requires-Dist: panel; extra == 'test-full' -Requires-Dist: paramiko; extra == 'test-full' -Requires-Dist: pyarrow; extra == 'test-full' -Requires-Dist: pyarrow>=1; extra == 'test-full' -Requires-Dist: pyftpdlib; extra == 'test-full' -Requires-Dist: pygit2; extra == 'test-full' -Requires-Dist: pytest; extra == 'test-full' -Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test-full' -Requires-Dist: pytest-benchmark; extra == 'test-full' -Requires-Dist: pytest-cov; extra == 'test-full' -Requires-Dist: pytest-mock; extra == 'test-full' -Requires-Dist: pytest-recording; extra == 'test-full' -Requires-Dist: pytest-rerunfailures; extra == 'test-full' -Requires-Dist: python-snappy; extra == 'test-full' -Requires-Dist: requests; extra == 'test-full' -Requires-Dist: smbprotocol; extra == 'test-full' -Requires-Dist: tqdm; extra == 'test-full' -Requires-Dist: urllib3; extra == 'test-full' -Requires-Dist: zarr; extra == 'test-full' -Requires-Dist: zstandard; (python_version < '3.14') and extra == 'test-full' -Provides-Extra: tqdm -Requires-Dist: tqdm; extra == 'tqdm' -Description-Content-Type: text/markdown - -# filesystem_spec - -[![PyPI version](https://badge.fury.io/py/fsspec.svg)](https://pypi.python.org/pypi/fsspec/) -[![Anaconda-Server Badge](https://anaconda.org/conda-forge/fsspec/badges/version.svg)](https://anaconda.org/conda-forge/fsspec) -![Build](https://github.com/fsspec/filesystem_spec/workflows/CI/badge.svg) -[![Docs](https://readthedocs.org/projects/filesystem-spec/badge/?version=latest)](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest) - -A specification for pythonic filesystems. - -## Install - -```bash -pip install fsspec -``` - -would install the base fsspec. Various optionally supported features might require specification of custom -extra require, e.g. `pip install fsspec[ssh]` will install dependencies for `ssh` backends support. -Use `pip install fsspec[full]` for installation of all known extra dependencies. - -Up-to-date package also provided through conda-forge distribution: - -```bash -conda install -c conda-forge fsspec -``` - - -## Purpose - -To produce a template or specification for a file-system interface, that specific implementations should follow, -so that applications making use of them can rely on a common behaviour and not have to worry about the specific -internal implementation decisions with any given backend. Many such implementations are included in this package, -or in sister projects such as `s3fs` and `gcsfs`. - -In addition, if this is well-designed, then additional functionality, such as a key-value store or FUSE -mounting of the file-system implementation may be available for all implementations "for free". - -## Documentation - -Please refer to [RTD](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest) - -## Develop - -fsspec uses GitHub Actions for CI. Environment files can be found -in the "ci/" directory. Note that the main environment is called "py38", -but it is expected that the version of python installed be adjustable at -CI runtime. For local use, pick a version suitable for you. - -```bash -# For a new environment (mamba / conda). -mamba create -n fsspec -c conda-forge python=3.10 -y -conda activate fsspec - -# Standard dev install with docs and tests. -pip install -e ".[dev,doc,test]" - -# Full tests except for downstream -pip install s3fs -pip uninstall s3fs -pip install -e .[dev,doc,test_full] -pip install s3fs --no-deps -pytest -v - -# Downstream tests. -sh install_s3fs.sh -# Windows powershell. -install_s3fs.sh -``` - -### Testing - -Tests can be run in the dev environment, if activated, via ``pytest fsspec``. - -The full fsspec suite requires a system-level docker, docker-compose, and fuse -installation. If only making changes to one backend implementation, it is -not generally necessary to run all tests locally. - -It is expected that contributors ensure that any change to fsspec does not -cause issues or regressions for either other fsspec-related packages such -as gcsfs and s3fs, nor for downstream users of fsspec. The "downstream" CI -run and corresponding environment file run a set of tests from the dask -test suite, and very minimal tests against pandas and zarr from the -test_downstream.py module in this repo. - -### Code Formatting - -fsspec uses [Black](https://black.readthedocs.io/en/stable) to ensure -a consistent code format throughout the project. -Run ``black fsspec`` from the root of the filesystem_spec repository to -auto-format your code. Additionally, many editors have plugins that will apply -``black`` as you edit files. ``black`` is included in the ``tox`` environments. - -Optionally, you may wish to setup [pre-commit hooks](https://pre-commit.com) to -automatically run ``black`` when you make a git commit. -Run ``pre-commit install --install-hooks`` from the root of the -filesystem_spec repository to setup pre-commit hooks. ``black`` will now be run -before you commit, reformatting any changed files. You can format without -committing via ``pre-commit run`` or skip these checks with ``git commit ---no-verify``. - -## Support - -Work on this repository is supported in part by: - -"Anaconda, Inc. - Advancing AI through open source." - -anaconda logo diff --git a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/RECORD b/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/RECORD deleted file mode 100644 index b3a1b4939fa41a1630cd6b3215ec59bc98be245e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/RECORD +++ /dev/null @@ -1,119 +0,0 @@ -fsspec-2026.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -fsspec-2026.2.0.dist-info/METADATA,sha256=Pw6QhbyXeg-elb0hpWPiQRpAeMD_ApJ9vdNFoYCnrPs,10524 -fsspec-2026.2.0.dist-info/RECORD,, -fsspec-2026.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87 -fsspec-2026.2.0.dist-info/licenses/LICENSE,sha256=LcNUls5TpzB5FcAIqESq1T53K0mzTN0ARFBnaRQH7JQ,1513 -fsspec/__init__.py,sha256=L7qwNBU1iMNQd8Of87HYSNFT9gWlNMSESaJC8fY0AaQ,2053 -fsspec/__pycache__/__init__.cpython-310.pyc,, -fsspec/__pycache__/_version.cpython-310.pyc,, -fsspec/__pycache__/archive.cpython-310.pyc,, -fsspec/__pycache__/asyn.cpython-310.pyc,, -fsspec/__pycache__/caching.cpython-310.pyc,, -fsspec/__pycache__/callbacks.cpython-310.pyc,, -fsspec/__pycache__/compression.cpython-310.pyc,, -fsspec/__pycache__/config.cpython-310.pyc,, -fsspec/__pycache__/conftest.cpython-310.pyc,, -fsspec/__pycache__/core.cpython-310.pyc,, -fsspec/__pycache__/dircache.cpython-310.pyc,, -fsspec/__pycache__/exceptions.cpython-310.pyc,, -fsspec/__pycache__/fuse.cpython-310.pyc,, -fsspec/__pycache__/generic.cpython-310.pyc,, -fsspec/__pycache__/gui.cpython-310.pyc,, -fsspec/__pycache__/json.cpython-310.pyc,, -fsspec/__pycache__/mapping.cpython-310.pyc,, -fsspec/__pycache__/parquet.cpython-310.pyc,, -fsspec/__pycache__/registry.cpython-310.pyc,, -fsspec/__pycache__/spec.cpython-310.pyc,, -fsspec/__pycache__/transaction.cpython-310.pyc,, -fsspec/__pycache__/utils.cpython-310.pyc,, -fsspec/_version.py,sha256=AEamMn8IHx_wGXrogRYVBycv6M5u2_UCmFedn7R8hYI,710 -fsspec/archive.py,sha256=vM6t_lgV6lBWbBYwpm3S4ofBQFQxUPr5KkDQrrQcQro,2411 -fsspec/asyn.py,sha256=LP_OicTWXmKHe31wBoYs2MrrNf8rmlhjVeGg5AqvVy8,36630 -fsspec/caching.py,sha256=8IJ4rgcWnvq_b_DqlcMGJ-K59d4Db5O9Gz8PkATAgHo,34023 -fsspec/callbacks.py,sha256=BDIwLzK6rr_0V5ch557fSzsivCElpdqhXr5dZ9Te-EE,9210 -fsspec/compression.py,sha256=3v_Fe39gzRRWfaeXpzNjAGPqgTzmETYRCo3qHVqD3po,5132 -fsspec/config.py,sha256=LF4Zmu1vhJW7Je9Q-cwkRc3xP7Rhyy7Xnwj26Z6sv2g,4279 -fsspec/conftest.py,sha256=uWfm_Qs5alPRxOhRpDfQ0-1jqSJ54pni4y96IxOREXM,3446 -fsspec/core.py,sha256=lc7XSnZU6_C6xljp7Z_xEGN3V7704hbeQLkxvPP0wds,24173 -fsspec/dircache.py,sha256=YzogWJrhEastHU7vWz-cJiJ7sdtLXFXhEpInGKd4EcM,2717 -fsspec/exceptions.py,sha256=pauSLDMxzTJMOjvX1WEUK0cMyFkrFxpWJsyFywav7A8,331 -fsspec/fuse.py,sha256=Q-3NOOyLqBfYa4Db5E19z_ZY36zzYHtIs1mOUasItBQ,10177 -fsspec/generic.py,sha256=9QHQYMNb-8w8-eYuIqShcTjO_LeHXFoQTyt8J5oEq5Q,13482 -fsspec/gui.py,sha256=CQ7QsrTpaDlWSLNOpwNoJc7khOcYXIZxmrAJN9bHWQU,14002 -fsspec/implementations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fsspec/implementations/__pycache__/__init__.cpython-310.pyc,, -fsspec/implementations/__pycache__/arrow.cpython-310.pyc,, -fsspec/implementations/__pycache__/asyn_wrapper.cpython-310.pyc,, -fsspec/implementations/__pycache__/cache_mapper.cpython-310.pyc,, -fsspec/implementations/__pycache__/cache_metadata.cpython-310.pyc,, -fsspec/implementations/__pycache__/cached.cpython-310.pyc,, -fsspec/implementations/__pycache__/chained.cpython-310.pyc,, -fsspec/implementations/__pycache__/dask.cpython-310.pyc,, -fsspec/implementations/__pycache__/data.cpython-310.pyc,, -fsspec/implementations/__pycache__/dbfs.cpython-310.pyc,, -fsspec/implementations/__pycache__/dirfs.cpython-310.pyc,, -fsspec/implementations/__pycache__/ftp.cpython-310.pyc,, -fsspec/implementations/__pycache__/gist.cpython-310.pyc,, -fsspec/implementations/__pycache__/git.cpython-310.pyc,, -fsspec/implementations/__pycache__/github.cpython-310.pyc,, -fsspec/implementations/__pycache__/http.cpython-310.pyc,, -fsspec/implementations/__pycache__/http_sync.cpython-310.pyc,, -fsspec/implementations/__pycache__/jupyter.cpython-310.pyc,, -fsspec/implementations/__pycache__/libarchive.cpython-310.pyc,, -fsspec/implementations/__pycache__/local.cpython-310.pyc,, -fsspec/implementations/__pycache__/memory.cpython-310.pyc,, -fsspec/implementations/__pycache__/reference.cpython-310.pyc,, -fsspec/implementations/__pycache__/sftp.cpython-310.pyc,, -fsspec/implementations/__pycache__/smb.cpython-310.pyc,, -fsspec/implementations/__pycache__/tar.cpython-310.pyc,, -fsspec/implementations/__pycache__/webhdfs.cpython-310.pyc,, -fsspec/implementations/__pycache__/zip.cpython-310.pyc,, -fsspec/implementations/arrow.py,sha256=8FhvcvOYLZNMMegCYFFCEHgEqig8AkOU7Ehb8XfcgnA,8890 -fsspec/implementations/asyn_wrapper.py,sha256=3lfJkGs6D_AwRBdxTSYlL-RCVdaXBZ9Itys2P5o5Si0,3738 -fsspec/implementations/cache_mapper.py,sha256=W4wlxyPxZbSp9ItJ0pYRVBMh6bw9eFypgP6kUYuuiI4,2421 -fsspec/implementations/cache_metadata.py,sha256=ipIe4S8nlU_M9oRJkvTqr-b0tcbXVZsxH3GxaelaNOY,8502 -fsspec/implementations/cached.py,sha256=67ipbj-3o8O1zMGR11rZ_IWCi_7h-VRYpEAowFXqrvA,36175 -fsspec/implementations/chained.py,sha256=iGivpNaHUFjB_ea0-HAPhcmm6CL8qnDf270PSj7JwuE,680 -fsspec/implementations/dask.py,sha256=CXZbJzIVOhKV8ILcxuy3bTvcacCueAbyQxmvAkbPkrk,4466 -fsspec/implementations/data.py,sha256=IhOGDkacYp5gkl9jhEu4msQfZPb0gS5Q_ml7Mbr6dgQ,1627 -fsspec/implementations/dbfs.py,sha256=1cvvC6KBWOb8pBVpc01xavVbEPXO1xsgZvPD7H73M9k,16217 -fsspec/implementations/dirfs.py,sha256=VNj6gPMfmmLPK4wxbtxt7mUqW7xkh2XDgMmEmSK_E1c,12166 -fsspec/implementations/ftp.py,sha256=fJhaMIKq2RvzYlLwG3bewy2jq4iRqjVt1aIpwtUIRwI,13235 -fsspec/implementations/gist.py,sha256=Y6jTDrE-wuTwvpPyAQDuuOMBGxlajafKWoB1_yX6jdY,8528 -fsspec/implementations/git.py,sha256=qBDWMz5LNllPqVjr5jf_1FuNha4P5lyQI3IlhYg-wUE,3731 -fsspec/implementations/github.py,sha256=aCsZL8UvXZgdkcB1RUs3DdLeNrjLKcFsFYeQFDWbBFo,11653 -fsspec/implementations/http.py,sha256=-AV5qeNpBWqnsmgnIO9Ily9B6--SR4sQJ7G4cBHarGE,30675 -fsspec/implementations/http_sync.py,sha256=UmBqd938ebwVjYgVtzg-ysG3ZoGhIJw0wFtQAfxV3Aw,30332 -fsspec/implementations/jupyter.py,sha256=q1PlQ66AAswGFyr8MFKWyobaV2YekMWRtqENBDQtD28,4002 -fsspec/implementations/libarchive.py,sha256=SpIA1F-zf7kb2-VYUVuhMrXTBOhBxUXKgEW1RaAdDoA,7098 -fsspec/implementations/local.py,sha256=ERDUdXdRI8AvRX06icXaDKwO-hcQgivc7EorqnayFFM,17028 -fsspec/implementations/memory.py,sha256=TDdLtSPWXxZKrrVGwmc3uS3oK_2mlcVTk2BiqR8IeII,10507 -fsspec/implementations/reference.py,sha256=xSUpB8o_QFAZiVJE2dt78QZMCUMLo5TaJ27e5DwDAfg,48814 -fsspec/implementations/sftp.py,sha256=L9pZOa6eLUWfJNtxkxeG2YI96SQwrM5Hj6ocyUZXUbg,5923 -fsspec/implementations/smb.py,sha256=5fhu8h06nOLBPh2c48aT7WBRqh9cEcbIwtyu06wTjec,15236 -fsspec/implementations/tar.py,sha256=dam78Tp_CozybNqCY2JYgGBS3Uc9FuJUAT9oB0lolOs,4111 -fsspec/implementations/webhdfs.py,sha256=osF2m0nhDil6sbMzYW_4DZzhxF4ygtb59XDiybd9Fyg,17589 -fsspec/implementations/zip.py,sha256=6f3z0s12tDbz1RMx7iDc3JDx730IAaKDdx7tf_XYDp0,6151 -fsspec/json.py,sha256=4EBZ-xOmRiyxmIqPIwxmDImosRQ7io7qBM2xjJPsEE4,3768 -fsspec/mapping.py,sha256=m2ndB_gtRBXYmNJg0Ie1-BVR75TFleHmIQBzC-yWhjU,8343 -fsspec/parquet.py,sha256=xGW3xfd9js7hrre7qN85XpSM0A1FObqkTcAv_H2xSwY,20505 -fsspec/registry.py,sha256=o7EGl8TEaLkcwN53X_103arzuzJeeOoVaNUWnPiXgf0,12148 -fsspec/spec.py,sha256=Ym-Ust6LRjHgbhrmvNqwOBZxoVnaw3g3xHXMZGHx_xg,77692 -fsspec/tests/abstract/__init__.py,sha256=4xUJrv7gDgc85xAOz1p-V_K1hrsdMWTSa0rviALlJk8,10181 -fsspec/tests/abstract/__pycache__/__init__.cpython-310.pyc,, -fsspec/tests/abstract/__pycache__/common.cpython-310.pyc,, -fsspec/tests/abstract/__pycache__/copy.cpython-310.pyc,, -fsspec/tests/abstract/__pycache__/get.cpython-310.pyc,, -fsspec/tests/abstract/__pycache__/mv.cpython-310.pyc,, -fsspec/tests/abstract/__pycache__/open.cpython-310.pyc,, -fsspec/tests/abstract/__pycache__/pipe.cpython-310.pyc,, -fsspec/tests/abstract/__pycache__/put.cpython-310.pyc,, -fsspec/tests/abstract/common.py,sha256=1GQwNo5AONzAnzZj0fWgn8NJPLXALehbsuGxS3FzWVU,4973 -fsspec/tests/abstract/copy.py,sha256=gU5-d97U3RSde35Vp4RxPY4rWwL744HiSrJ8IBOp9-8,19967 -fsspec/tests/abstract/get.py,sha256=vNR4HztvTR7Cj56AMo7_tx7TeYz1Jgr_2Wb8Lv-UiBY,20755 -fsspec/tests/abstract/mv.py,sha256=k8eUEBIrRrGMsBY5OOaDXdGnQUKGwDIfQyduB6YD3Ns,1982 -fsspec/tests/abstract/open.py,sha256=Fi2PBPYLbRqysF8cFm0rwnB41kMdQVYjq8cGyDXp3BU,329 -fsspec/tests/abstract/pipe.py,sha256=LFzIrLCB5GLXf9rzFKJmE8AdG7LQ_h4bJo70r8FLPqM,402 -fsspec/tests/abstract/put.py,sha256=7aih17OKB_IZZh1Mkq1eBDIjobhtMQmI8x-Pw-S_aZk,21201 -fsspec/transaction.py,sha256=xliRG6U2Zf3khG4xcw9WiB-yAoqJSHEGK_VjHOdtgo0,2398 -fsspec/utils.py,sha256=E24ji0XLWC6n3bw2sHA28OYxrGU9Wy_al2XydsRgrRk,23623 diff --git a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/WHEEL b/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/WHEEL deleted file mode 100644 index ae8ec1bdaa94d726ceb907542d76cbd5d38cafcd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.28.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/licenses/LICENSE deleted file mode 100644 index 67590a5e5be5a5a2dde3fe53a7512e404a896c22..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec-2026.2.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2018, Martin Durant -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.10/site-packages/fsspec/__init__.py b/venv/lib/python3.10/site-packages/fsspec/__init__.py deleted file mode 100644 index 452c78a055e72a6d04f1013d1a98fda33fdc449e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/__init__.py +++ /dev/null @@ -1,71 +0,0 @@ -from . import caching -from ._version import __version__ # noqa: F401 -from .callbacks import Callback -from .compression import available_compressions -from .core import get_fs_token_paths, open, open_files, open_local, url_to_fs -from .exceptions import FSTimeoutError -from .mapping import FSMap, get_mapper -from .registry import ( - available_protocols, - filesystem, - get_filesystem_class, - register_implementation, - registry, -) -from .spec import AbstractFileSystem - -__all__ = [ - "AbstractFileSystem", - "FSTimeoutError", - "FSMap", - "filesystem", - "register_implementation", - "get_filesystem_class", - "get_fs_token_paths", - "get_mapper", - "open", - "open_files", - "open_local", - "registry", - "caching", - "Callback", - "available_protocols", - "available_compressions", - "url_to_fs", -] - - -def process_entries(): - try: - from importlib.metadata import entry_points - except ImportError: - return - if entry_points is not None: - try: - eps = entry_points() - except TypeError: - pass # importlib-metadata < 0.8 - else: - if hasattr(eps, "select"): # Python 3.10+ / importlib_metadata >= 3.9.0 - specs = eps.select(group="fsspec.specs") - else: - specs = eps.get("fsspec.specs", []) - registered_names = {} - for spec in specs: - err_msg = f"Unable to load filesystem from {spec}" - name = spec.name - if name in registered_names: - continue - registered_names[name] = True - register_implementation( - name, - spec.value.replace(":", "."), - errtxt=err_msg, - # We take our implementations as the ones to overload with if - # for some reason we encounter some, may be the same, already - # registered - clobber=True, - ) - - -process_entries() diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index b5c3159c1367e70f760e7d4b3bd42c611b6a01da..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/_version.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/_version.cpython-310.pyc deleted file mode 100644 index ef4b0508bb156c58a193de2a920650a28de40ebc..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/_version.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/archive.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/archive.cpython-310.pyc deleted file mode 100644 index cd2a928aad2520c20aac150187814a723adc8630..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/archive.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/asyn.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/asyn.cpython-310.pyc deleted file mode 100644 index df7b61f65202dfdd54aae1f7030c4602b654db72..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/asyn.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/caching.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/caching.cpython-310.pyc deleted file mode 100644 index 3891c0fa837eb5b616e9e0a3fd03726b93a24744..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/caching.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/callbacks.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/callbacks.cpython-310.pyc deleted file mode 100644 index cfec5f94e50aa019751ea1561e522576d37b89ce..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/callbacks.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/compression.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/compression.cpython-310.pyc deleted file mode 100644 index 00011ce5bbf3e0e7066eb3639ae840a7ea380102..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/compression.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/config.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/config.cpython-310.pyc deleted file mode 100644 index de633e5b4d7c2901ad09a85071c53785faef002b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/config.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/conftest.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/conftest.cpython-310.pyc deleted file mode 100644 index 85ea78498d9568cc002ff94074ab0cfd309fe581..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/conftest.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/core.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/core.cpython-310.pyc deleted file mode 100644 index 433de20a7746831a355aa4774cac95ec137aa2a7..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/core.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/dircache.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/dircache.cpython-310.pyc deleted file mode 100644 index c5ff8d7cb791ae5ded1215ccfbabde5e1ab7b66b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/dircache.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/exceptions.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/exceptions.cpython-310.pyc deleted file mode 100644 index b52df4fb9eea51089fddeaed4f7081f0da83bd97..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/exceptions.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/fuse.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/fuse.cpython-310.pyc deleted file mode 100644 index 271f41b455ad7a494803ff32ac340d24d3904109..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/fuse.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/generic.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/generic.cpython-310.pyc deleted file mode 100644 index 2d9d0802296f0207d5682edd0d0e623dfe5f7de3..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/generic.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/gui.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/gui.cpython-310.pyc deleted file mode 100644 index d23ab430adb50a52a800edf0ffe1f208efba5895..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/gui.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/json.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/json.cpython-310.pyc deleted file mode 100644 index 49d26566e20544937827b74fe8387c70794a4a05..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/json.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/mapping.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/mapping.cpython-310.pyc deleted file mode 100644 index 59c2260ed9e2c70349dc000865f5e993928f472b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/mapping.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/parquet.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/parquet.cpython-310.pyc deleted file mode 100644 index 30d7a95a85a947b9c06e9ec90744af5665ad617e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/parquet.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/registry.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/registry.cpython-310.pyc deleted file mode 100644 index b1e6f715609b3fc665fafb3e4e94cd3b8c817758..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/registry.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/spec.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/spec.cpython-310.pyc deleted file mode 100644 index 7ba3fa82b1fc4eee3a9cb7f7e15bd427e0a00316..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/spec.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/transaction.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/transaction.cpython-310.pyc deleted file mode 100644 index 831238f7670dfe9d75469bbaa9313a70b6bc1f19..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/transaction.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/__pycache__/utils.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/__pycache__/utils.cpython-310.pyc deleted file mode 100644 index 67d50db26391dca17a07e3906b2485bf4ba96133..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/__pycache__/utils.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/_version.py b/venv/lib/python3.10/site-packages/fsspec/_version.py deleted file mode 100644 index 43aa383e6690a59bd71080d1dcffa276ea25ad29..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/_version.py +++ /dev/null @@ -1,34 +0,0 @@ -# file generated by setuptools-scm -# don't change, don't track in version control - -__all__ = [ - "__version__", - "__version_tuple__", - "version", - "version_tuple", - "__commit_id__", - "commit_id", -] - -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import Tuple - from typing import Union - - VERSION_TUPLE = Tuple[Union[int, str], ...] - COMMIT_ID = Union[str, None] -else: - VERSION_TUPLE = object - COMMIT_ID = object - -version: str -__version__: str -__version_tuple__: VERSION_TUPLE -version_tuple: VERSION_TUPLE -commit_id: COMMIT_ID -__commit_id__: COMMIT_ID - -__version__ = version = '2026.2.0' -__version_tuple__ = version_tuple = (2026, 2, 0) - -__commit_id__ = commit_id = None diff --git a/venv/lib/python3.10/site-packages/fsspec/archive.py b/venv/lib/python3.10/site-packages/fsspec/archive.py deleted file mode 100644 index 13a4da8df7c9405297cdd7d37476be2f725b2f57..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/archive.py +++ /dev/null @@ -1,75 +0,0 @@ -import operator - -from fsspec import AbstractFileSystem -from fsspec.utils import tokenize - - -class AbstractArchiveFileSystem(AbstractFileSystem): - """ - A generic superclass for implementing Archive-based filesystems. - - Currently, it is shared amongst - :class:`~fsspec.implementations.zip.ZipFileSystem`, - :class:`~fsspec.implementations.libarchive.LibArchiveFileSystem` and - :class:`~fsspec.implementations.tar.TarFileSystem`. - """ - - def __str__(self): - return f"" - - __repr__ = __str__ - - def ukey(self, path): - return tokenize(path, self.fo, self.protocol) - - def _all_dirnames(self, paths): - """Returns *all* directory names for each path in paths, including intermediate - ones. - - Parameters - ---------- - paths: Iterable of path strings - """ - if len(paths) == 0: - return set() - - dirnames = {self._parent(path) for path in paths} - {self.root_marker} - return dirnames | self._all_dirnames(dirnames) - - def info(self, path, **kwargs): - self._get_dirs() - path = self._strip_protocol(path) - if path in {"", "/"} and self.dir_cache: - return {"name": "", "type": "directory", "size": 0} - if path in self.dir_cache: - return self.dir_cache[path] - elif path + "/" in self.dir_cache: - return self.dir_cache[path + "/"] - else: - raise FileNotFoundError(path) - - def ls(self, path, detail=True, **kwargs): - self._get_dirs() - paths = {} - for p, f in self.dir_cache.items(): - p = p.rstrip("/") - if "/" in p: - root = p.rsplit("/", 1)[0] - else: - root = "" - if root == path.rstrip("/"): - paths[p] = f - elif all( - (a == b) - for a, b in zip(path.split("/"), [""] + p.strip("/").split("/")) - ): - # root directory entry - ppath = p.rstrip("/").split("/", 1)[0] - if ppath not in paths: - out = {"name": ppath, "size": 0, "type": "directory"} - paths[ppath] = out - if detail: - out = sorted(paths.values(), key=operator.itemgetter("name")) - return out - else: - return sorted(paths) diff --git a/venv/lib/python3.10/site-packages/fsspec/asyn.py b/venv/lib/python3.10/site-packages/fsspec/asyn.py deleted file mode 100644 index 360758ac64608331d0976b8ee17c2c02d1f3e6d7..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/asyn.py +++ /dev/null @@ -1,1103 +0,0 @@ -import asyncio -import asyncio.events -import functools -import inspect -import io -import numbers -import os -import re -import threading -from collections.abc import Iterable -from glob import has_magic -from typing import TYPE_CHECKING - -from .callbacks import DEFAULT_CALLBACK -from .exceptions import FSTimeoutError -from .implementations.local import LocalFileSystem, make_path_posix, trailing_sep -from .spec import AbstractBufferedFile, AbstractFileSystem -from .utils import glob_translate, is_exception, other_paths - -private = re.compile("_[^_]") -iothread = [None] # dedicated fsspec IO thread -loop = [None] # global event loop for any non-async instance -_lock = None # global lock placeholder -get_running_loop = asyncio.get_running_loop - - -def get_lock(): - """Allocate or return a threading lock. - - The lock is allocated on first use to allow setting one lock per forked process. - """ - global _lock - if not _lock: - _lock = threading.Lock() - return _lock - - -def reset_lock(): - """Reset the global lock. - - This should be called only on the init of a forked process to reset the lock to - None, enabling the new forked process to get a new lock. - """ - global _lock - - iothread[0] = None - loop[0] = None - _lock = None - - -async def _runner(event, coro, result, timeout=None): - timeout = timeout if timeout else None # convert 0 or 0.0 to None - if timeout is not None: - coro = asyncio.wait_for(coro, timeout=timeout) - try: - result[0] = await coro - except Exception as ex: - result[0] = ex - finally: - event.set() - - -def sync(loop, func, *args, timeout=None, **kwargs): - """ - Make loop run coroutine until it returns. Runs in other thread - - Examples - -------- - >>> fsspec.asyn.sync(fsspec.asyn.get_loop(), func, *args, - timeout=timeout, **kwargs) - """ - timeout = timeout if timeout else None # convert 0 or 0.0 to None - # NB: if the loop is not running *yet*, it is OK to submit work - # and we will wait for it - if loop is None or loop.is_closed(): - raise RuntimeError("Loop is not running") - try: - loop0 = asyncio.events.get_running_loop() - if loop0 is loop: - raise NotImplementedError("Calling sync() from within a running loop") - except NotImplementedError: - raise - except RuntimeError: - pass - coro = func(*args, **kwargs) - result = [None] - event = threading.Event() - asyncio.run_coroutine_threadsafe(_runner(event, coro, result, timeout), loop) - while True: - # this loops allows thread to get interrupted - if event.wait(1): - break - if timeout is not None: - timeout -= 1 - if timeout < 0: - raise FSTimeoutError - - return_result = result[0] - if isinstance(return_result, asyncio.TimeoutError): - # suppress asyncio.TimeoutError, raise FSTimeoutError - raise FSTimeoutError from return_result - elif isinstance(return_result, BaseException): - raise return_result - else: - return return_result - - -def sync_wrapper(func, obj=None): - """Given a function, make so can be called in blocking contexts - - Leave obj=None if defining within a class. Pass the instance if attaching - as an attribute of the instance. - """ - - @functools.wraps(func) - def wrapper(*args, **kwargs): - self = obj or args[0] - return sync(self.loop, func, *args, **kwargs) - - return wrapper - - -def get_loop(): - """Create or return the default fsspec IO loop - - The loop will be running on a separate thread. - """ - if loop[0] is None: - with get_lock(): - # repeat the check just in case the loop got filled between the - # previous two calls from another thread - if loop[0] is None: - loop[0] = asyncio.new_event_loop() - th = threading.Thread(target=loop[0].run_forever, name="fsspecIO") - th.daemon = True - th.start() - iothread[0] = th - return loop[0] - - -def reset_after_fork(): - global lock - loop[0] = None - iothread[0] = None - lock = None - - -if hasattr(os, "register_at_fork"): - # should be posix; this will do nothing for spawn or forkserver subprocesses - os.register_at_fork(after_in_child=reset_after_fork) - - -if TYPE_CHECKING: - import resource - - ResourceError = resource.error -else: - try: - import resource - except ImportError: - resource = None - ResourceError = OSError - else: - ResourceError = getattr(resource, "error", OSError) - -_DEFAULT_BATCH_SIZE = 128 -_NOFILES_DEFAULT_BATCH_SIZE = 1280 - - -def _get_batch_size(nofiles=False): - from fsspec.config import conf - - if nofiles: - if "nofiles_gather_batch_size" in conf: - return conf["nofiles_gather_batch_size"] - else: - if "gather_batch_size" in conf: - return conf["gather_batch_size"] - if nofiles: - return _NOFILES_DEFAULT_BATCH_SIZE - if resource is None: - return _DEFAULT_BATCH_SIZE - - try: - soft_limit, _ = resource.getrlimit(resource.RLIMIT_NOFILE) - except (ImportError, ValueError, ResourceError): - return _DEFAULT_BATCH_SIZE - - if soft_limit == resource.RLIM_INFINITY: - return -1 - else: - return soft_limit // 8 - - -def running_async() -> bool: - """Being executed by an event loop?""" - try: - asyncio.get_running_loop() - return True - except RuntimeError: - return False - - -async def _run_coros_in_chunks( - coros, - batch_size=None, - callback=DEFAULT_CALLBACK, - timeout=None, - return_exceptions=False, - nofiles=False, -): - """Run the given coroutines in chunks. - - Parameters - ---------- - coros: list of coroutines to run - batch_size: int or None - Number of coroutines to submit/wait on simultaneously. - If -1, then it will not be any throttling. If - None, it will be inferred from _get_batch_size() - callback: fsspec.callbacks.Callback instance - Gets a relative_update when each coroutine completes - timeout: number or None - If given, each coroutine times out after this time. Note that, since - there are multiple batches, the total run time of this function will in - general be longer - return_exceptions: bool - Same meaning as in asyncio.gather - nofiles: bool - If inferring the batch_size, does this operation involve local files? - If yes, you normally expect smaller batches. - """ - - if batch_size is None: - batch_size = _get_batch_size(nofiles=nofiles) - - if batch_size == -1: - batch_size = len(coros) - - assert batch_size > 0 - - async def _run_coro(coro, i): - try: - return await asyncio.wait_for(coro, timeout=timeout), i - except Exception as e: - if not return_exceptions: - raise - return e, i - finally: - callback.relative_update(1) - - i = 0 - n = len(coros) - results = [None] * n - pending = set() - - while pending or i < n: - while len(pending) < batch_size and i < n: - pending.add(asyncio.ensure_future(_run_coro(coros[i], i))) - i += 1 - - if not pending: - break - - done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED) - while done: - result, k = await done.pop() - results[k] = result - - return results - - -# these methods should be implemented as async by any async-able backend -async_methods = [ - "_ls", - "_cat_file", - "_get_file", - "_put_file", - "_rm_file", - "_cp_file", - "_pipe_file", - "_expand_path", - "_info", - "_isfile", - "_isdir", - "_exists", - "_walk", - "_glob", - "_find", - "_du", - "_size", - "_mkdir", - "_makedirs", -] - - -class AsyncFileSystem(AbstractFileSystem): - """Async file operations, default implementations - - Passes bulk operations to asyncio.gather for concurrent operation. - - Implementations that have concurrent batch operations and/or async methods - should inherit from this class instead of AbstractFileSystem. Docstrings are - copied from the un-underscored method in AbstractFileSystem, if not given. - """ - - # note that methods do not have docstring here; they will be copied - # for _* methods and inferred for overridden methods. - - async_impl = True - mirror_sync_methods = True - disable_throttling = False - - def __init__(self, *args, asynchronous=False, loop=None, batch_size=None, **kwargs): - self.asynchronous = asynchronous - self._pid = os.getpid() - if not asynchronous: - self._loop = loop or get_loop() - else: - self._loop = None - self.batch_size = batch_size - super().__init__(*args, **kwargs) - - @property - def loop(self): - if self._pid != os.getpid(): - raise RuntimeError("This class is not fork-safe") - return self._loop - - async def _rm_file(self, path, **kwargs): - if ( - inspect.iscoroutinefunction(self._rm) - and type(self)._rm is not AsyncFileSystem._rm - ): - return await self._rm(path, recursive=False, batch_size=1, **kwargs) - raise NotImplementedError - - async def _rm(self, path, recursive=False, batch_size=None, **kwargs): - # TODO: implement on_error - batch_size = batch_size or self.batch_size - path = await self._expand_path(path, recursive=recursive) - return await _run_coros_in_chunks( - [self._rm_file(p, **kwargs) for p in reversed(path)], - batch_size=batch_size, - nofiles=True, - ) - - async def _cp_file(self, path1, path2, **kwargs): - raise NotImplementedError - - async def _mv_file(self, path1, path2): - await self._cp_file(path1, path2) - await self._rm_file(path1) - - async def _copy( - self, - path1, - path2, - recursive=False, - on_error=None, - maxdepth=None, - batch_size=None, - **kwargs, - ): - if on_error is None and recursive: - on_error = "ignore" - elif on_error is None: - on_error = "raise" - - if isinstance(path1, list) and isinstance(path2, list): - # No need to expand paths when both source and destination - # are provided as lists - paths1 = path1 - paths2 = path2 - else: - source_is_str = isinstance(path1, str) - paths1 = await self._expand_path( - path1, maxdepth=maxdepth, recursive=recursive - ) - if source_is_str and (not recursive or maxdepth is not None): - # Non-recursive glob does not copy directories - paths1 = [ - p for p in paths1 if not (trailing_sep(p) or await self._isdir(p)) - ] - if not paths1: - return - - source_is_file = len(paths1) == 1 - dest_is_dir = isinstance(path2, str) and ( - trailing_sep(path2) or await self._isdir(path2) - ) - - exists = source_is_str and ( - (has_magic(path1) and source_is_file) - or (not has_magic(path1) and dest_is_dir and not trailing_sep(path1)) - ) - paths2 = other_paths( - paths1, - path2, - exists=exists, - flatten=not source_is_str, - ) - - batch_size = batch_size or self.batch_size - coros = [self._cp_file(p1, p2, **kwargs) for p1, p2 in zip(paths1, paths2)] - result = await _run_coros_in_chunks( - coros, batch_size=batch_size, return_exceptions=True, nofiles=True - ) - - for ex in filter(is_exception, result): - if on_error == "ignore" and isinstance(ex, FileNotFoundError): - continue - raise ex - - async def _pipe_file(self, path, value, mode="overwrite", **kwargs): - raise NotImplementedError - - async def _pipe(self, path, value=None, batch_size=None, **kwargs): - if isinstance(path, str): - path = {path: value} - batch_size = batch_size or self.batch_size - return await _run_coros_in_chunks( - [self._pipe_file(k, v, **kwargs) for k, v in path.items()], - batch_size=batch_size, - nofiles=True, - ) - - async def _process_limits(self, url, start, end): - """Helper for "Range"-based _cat_file""" - size = None - suff = False - if start is not None and start < 0: - # if start is negative and end None, end is the "suffix length" - if end is None: - end = -start - start = "" - suff = True - else: - size = size or (await self._info(url))["size"] - start = size + start - elif start is None: - start = 0 - if not suff: - if end is not None and end < 0: - if start is not None: - size = size or (await self._info(url))["size"] - end = size + end - elif end is None: - end = "" - if isinstance(end, numbers.Integral): - end -= 1 # bytes range is inclusive - return f"bytes={start}-{end}" - - async def _cat_file(self, path, start=None, end=None, **kwargs): - raise NotImplementedError - - async def _cat( - self, path, recursive=False, on_error="raise", batch_size=None, **kwargs - ): - paths = await self._expand_path(path, recursive=recursive) - coros = [self._cat_file(path, **kwargs) for path in paths] - batch_size = batch_size or self.batch_size - out = await _run_coros_in_chunks( - coros, batch_size=batch_size, nofiles=True, return_exceptions=True - ) - if on_error == "raise": - ex = next(filter(is_exception, out), False) - if ex: - raise ex - if ( - len(paths) > 1 - or isinstance(path, list) - or paths[0] != self._strip_protocol(path) - ): - return { - k: v - for k, v in zip(paths, out) - if on_error != "omit" or not is_exception(v) - } - else: - return out[0] - - async def _cat_ranges( - self, - paths, - starts, - ends, - max_gap=None, - batch_size=None, - on_error="return", - **kwargs, - ): - """Get the contents of byte ranges from one or more files - - Parameters - ---------- - paths: list - A list of of filepaths on this filesystems - starts, ends: int or list - Bytes limits of the read. If using a single int, the same value will be - used to read all the specified files. - """ - # TODO: on_error - if max_gap is not None: - # use utils.merge_offset_ranges - raise NotImplementedError - if not isinstance(paths, list): - raise TypeError - if not isinstance(starts, Iterable): - starts = [starts] * len(paths) - if not isinstance(ends, Iterable): - ends = [ends] * len(paths) - if len(starts) != len(paths) or len(ends) != len(paths): - raise ValueError - coros = [ - self._cat_file(p, start=s, end=e, **kwargs) - for p, s, e in zip(paths, starts, ends) - ] - batch_size = batch_size or self.batch_size - return await _run_coros_in_chunks( - coros, batch_size=batch_size, nofiles=True, return_exceptions=True - ) - - async def _put_file(self, lpath, rpath, mode="overwrite", **kwargs): - raise NotImplementedError - - async def _put( - self, - lpath, - rpath, - recursive=False, - callback=DEFAULT_CALLBACK, - batch_size=None, - maxdepth=None, - **kwargs, - ): - """Copy file(s) from local. - - Copies a specific file or tree of files (if recursive=True). If rpath - ends with a "/", it will be assumed to be a directory, and target files - will go within. - - The put_file method will be called concurrently on a batch of files. The - batch_size option can configure the amount of futures that can be executed - at the same time. If it is -1, then all the files will be uploaded concurrently. - The default can be set for this instance by passing "batch_size" in the - constructor, or for all instances by setting the "gather_batch_size" key - in ``fsspec.config.conf``, falling back to 1/8th of the system limit . - """ - if isinstance(lpath, list) and isinstance(rpath, list): - # No need to expand paths when both source and destination - # are provided as lists - rpaths = rpath - lpaths = lpath - else: - source_is_str = isinstance(lpath, str) - if source_is_str: - lpath = make_path_posix(lpath) - fs = LocalFileSystem() - lpaths = fs.expand_path(lpath, recursive=recursive, maxdepth=maxdepth) - if source_is_str and (not recursive or maxdepth is not None): - # Non-recursive glob does not copy directories - lpaths = [p for p in lpaths if not (trailing_sep(p) or fs.isdir(p))] - if not lpaths: - return - - source_is_file = len(lpaths) == 1 - dest_is_dir = isinstance(rpath, str) and ( - trailing_sep(rpath) or await self._isdir(rpath) - ) - - rpath = self._strip_protocol(rpath) - exists = source_is_str and ( - (has_magic(lpath) and source_is_file) - or (not has_magic(lpath) and dest_is_dir and not trailing_sep(lpath)) - ) - rpaths = other_paths( - lpaths, - rpath, - exists=exists, - flatten=not source_is_str, - ) - - is_dir = {l: os.path.isdir(l) for l in lpaths} - rdirs = [r for l, r in zip(lpaths, rpaths) if is_dir[l]] - file_pairs = [(l, r) for l, r in zip(lpaths, rpaths) if not is_dir[l]] - - await asyncio.gather(*[self._makedirs(d, exist_ok=True) for d in rdirs]) - batch_size = batch_size or self.batch_size - - coros = [] - callback.set_size(len(file_pairs)) - for lfile, rfile in file_pairs: - put_file = callback.branch_coro(self._put_file) - coros.append(put_file(lfile, rfile, **kwargs)) - - return await _run_coros_in_chunks( - coros, batch_size=batch_size, callback=callback - ) - - async def _get_file(self, rpath, lpath, **kwargs): - raise NotImplementedError - - async def _get( - self, - rpath, - lpath, - recursive=False, - callback=DEFAULT_CALLBACK, - maxdepth=None, - **kwargs, - ): - """Copy file(s) to local. - - Copies a specific file or tree of files (if recursive=True). If lpath - ends with a "/", it will be assumed to be a directory, and target files - will go within. Can submit a list of paths, which may be glob-patterns - and will be expanded. - - The get_file method will be called concurrently on a batch of files. The - batch_size option can configure the amount of futures that can be executed - at the same time. If it is -1, then all the files will be uploaded concurrently. - The default can be set for this instance by passing "batch_size" in the - constructor, or for all instances by setting the "gather_batch_size" key - in ``fsspec.config.conf``, falling back to 1/8th of the system limit . - """ - if isinstance(lpath, list) and isinstance(rpath, list): - # No need to expand paths when both source and destination - # are provided as lists - rpaths = rpath - lpaths = lpath - else: - source_is_str = isinstance(rpath, str) - # First check for rpath trailing slash as _strip_protocol removes it. - source_not_trailing_sep = source_is_str and not trailing_sep(rpath) - rpath = self._strip_protocol(rpath) - rpaths = await self._expand_path( - rpath, recursive=recursive, maxdepth=maxdepth - ) - if source_is_str and (not recursive or maxdepth is not None): - # Non-recursive glob does not copy directories - rpaths = [ - p for p in rpaths if not (trailing_sep(p) or await self._isdir(p)) - ] - if not rpaths: - return - - lpath = make_path_posix(lpath) - source_is_file = len(rpaths) == 1 - dest_is_dir = isinstance(lpath, str) and ( - trailing_sep(lpath) or LocalFileSystem().isdir(lpath) - ) - - exists = source_is_str and ( - (has_magic(rpath) and source_is_file) - or (not has_magic(rpath) and dest_is_dir and source_not_trailing_sep) - ) - lpaths = other_paths( - rpaths, - lpath, - exists=exists, - flatten=not source_is_str, - ) - - [os.makedirs(os.path.dirname(lp), exist_ok=True) for lp in lpaths] - batch_size = kwargs.pop("batch_size", self.batch_size) - - coros = [] - callback.set_size(len(lpaths)) - for lpath, rpath in zip(lpaths, rpaths): - get_file = callback.branch_coro(self._get_file) - coros.append(get_file(rpath, lpath, **kwargs)) - return await _run_coros_in_chunks( - coros, batch_size=batch_size, callback=callback - ) - - async def _isfile(self, path): - try: - return (await self._info(path))["type"] == "file" - except: # noqa: E722 - return False - - async def _isdir(self, path): - try: - return (await self._info(path))["type"] == "directory" - except OSError: - return False - - async def _size(self, path): - return (await self._info(path)).get("size", None) - - async def _sizes(self, paths, batch_size=None): - batch_size = batch_size or self.batch_size - return await _run_coros_in_chunks( - [self._size(p) for p in paths], batch_size=batch_size - ) - - async def _exists(self, path, **kwargs): - try: - await self._info(path, **kwargs) - return True - except FileNotFoundError: - return False - - async def _info(self, path, **kwargs): - raise NotImplementedError - - async def _ls(self, path, detail=True, **kwargs): - raise NotImplementedError - - async def _walk(self, path, maxdepth=None, on_error="omit", **kwargs): - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - - path = self._strip_protocol(path) - full_dirs = {} - dirs = {} - files = {} - - detail = kwargs.pop("detail", False) - try: - listing = await self._ls(path, detail=True, **kwargs) - except (FileNotFoundError, OSError) as e: - if on_error == "raise": - raise - elif callable(on_error): - on_error(e) - if detail: - yield path, {}, {} - else: - yield path, [], [] - return - - for info in listing: - # each info name must be at least [path]/part , but here - # we check also for names like [path]/part/ - pathname = info["name"].rstrip("/") - name = pathname.rsplit("/", 1)[-1] - if info["type"] == "directory" and pathname != path: - # do not include "self" path - full_dirs[name] = pathname - dirs[name] = info - elif pathname == path: - # file-like with same name as give path - files[""] = info - else: - files[name] = info - - if detail: - yield path, dirs, files - else: - yield path, list(dirs), list(files) - - if maxdepth is not None: - maxdepth -= 1 - if maxdepth < 1: - return - - for d in dirs: - async for _ in self._walk( - full_dirs[d], maxdepth=maxdepth, detail=detail, **kwargs - ): - yield _ - - async def _glob(self, path, maxdepth=None, **kwargs): - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - - import re - - seps = (os.path.sep, os.path.altsep) if os.path.altsep else (os.path.sep,) - ends_with_sep = path.endswith(seps) # _strip_protocol strips trailing slash - path = self._strip_protocol(path) - append_slash_to_dirname = ends_with_sep or path.endswith( - tuple(sep + "**" for sep in seps) - ) - idx_star = path.find("*") if path.find("*") >= 0 else len(path) - idx_qmark = path.find("?") if path.find("?") >= 0 else len(path) - idx_brace = path.find("[") if path.find("[") >= 0 else len(path) - - min_idx = min(idx_star, idx_qmark, idx_brace) - - detail = kwargs.pop("detail", False) - withdirs = kwargs.pop("withdirs", True) - - if not has_magic(path): - if await self._exists(path, **kwargs): - if not detail: - return [path] - else: - return {path: await self._info(path, **kwargs)} - else: - if not detail: - return [] # glob of non-existent returns empty - else: - return {} - elif "/" in path[:min_idx]: - min_idx = path[:min_idx].rindex("/") - root = path[: min_idx + 1] - depth = path[min_idx + 1 :].count("/") + 1 - else: - root = "" - depth = path[min_idx + 1 :].count("/") + 1 - - if "**" in path: - if maxdepth is not None: - idx_double_stars = path.find("**") - depth_double_stars = path[idx_double_stars:].count("/") + 1 - depth = depth - depth_double_stars + maxdepth - else: - depth = None - - allpaths = await self._find( - root, maxdepth=depth, withdirs=withdirs, detail=True, **kwargs - ) - - pattern = glob_translate(path + ("/" if ends_with_sep else "")) - pattern = re.compile(pattern) - - out = { - p: info - for p, info in sorted(allpaths.items()) - if pattern.match( - p + "/" - if append_slash_to_dirname and info["type"] == "directory" - else p - ) - } - - if detail: - return out - else: - return list(out) - - async def _du(self, path, total=True, maxdepth=None, **kwargs): - sizes = {} - # async for? - for f in await self._find(path, maxdepth=maxdepth, **kwargs): - info = await self._info(f) - sizes[info["name"]] = info["size"] - if total: - return sum(sizes.values()) - else: - return sizes - - async def _find(self, path, maxdepth=None, withdirs=False, **kwargs): - path = self._strip_protocol(path) - out = {} - detail = kwargs.pop("detail", False) - - # Add the root directory if withdirs is requested - # This is needed for posix glob compliance - if withdirs and path != "" and await self._isdir(path): - out[path] = await self._info(path) - - # async for? - async for _, dirs, files in self._walk(path, maxdepth, detail=True, **kwargs): - if withdirs: - files.update(dirs) - out.update({info["name"]: info for name, info in files.items()}) - if not out and (await self._isfile(path)): - # walk works on directories, but find should also return [path] - # when path happens to be a file - out[path] = {} - names = sorted(out) - if not detail: - return names - else: - return {name: out[name] for name in names} - - async def _expand_path(self, path, recursive=False, maxdepth=None): - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - - if isinstance(path, str): - out = await self._expand_path([path], recursive, maxdepth) - else: - out = set() - path = [self._strip_protocol(p) for p in path] - for p in path: # can gather here - if has_magic(p): - bit = set(await self._glob(p, maxdepth=maxdepth)) - out |= bit - if recursive: - # glob call above expanded one depth so if maxdepth is defined - # then decrement it in expand_path call below. If it is zero - # after decrementing then avoid expand_path call. - if maxdepth is not None and maxdepth <= 1: - continue - out |= set( - await self._expand_path( - list(bit), - recursive=recursive, - maxdepth=maxdepth - 1 if maxdepth is not None else None, - ) - ) - continue - elif recursive: - rec = set(await self._find(p, maxdepth=maxdepth, withdirs=True)) - out |= rec - if p not in out and (recursive is False or (await self._exists(p))): - # should only check once, for the root - out.add(p) - if not out: - raise FileNotFoundError(path) - return sorted(out) - - async def _mkdir(self, path, create_parents=True, **kwargs): - pass # not necessary to implement, may not have directories - - async def _makedirs(self, path, exist_ok=False): - pass # not necessary to implement, may not have directories - - async def open_async(self, path, mode="rb", **kwargs): - if "b" not in mode or kwargs.get("compression"): - raise ValueError - raise NotImplementedError - - -def mirror_sync_methods(obj): - """Populate sync and async methods for obj - - For each method will create a sync version if the name refers to an async method - (coroutine) and there is no override in the child class; will create an async - method for the corresponding sync method if there is no implementation. - - Uses the methods specified in - - async_methods: the set that an implementation is expected to provide - - default_async_methods: that can be derived from their sync version in - AbstractFileSystem - - AsyncFileSystem: async-specific default coroutines - """ - from fsspec import AbstractFileSystem - - for method in async_methods + dir(AsyncFileSystem): - if not method.startswith("_"): - continue - smethod = method[1:] - if private.match(method): - isco = inspect.iscoroutinefunction(getattr(obj, method, None)) - unsync = getattr(getattr(obj, smethod, False), "__func__", None) - is_default = unsync is getattr(AbstractFileSystem, smethod, "") - if isco and is_default: - mth = sync_wrapper(getattr(obj, method), obj=obj) - setattr(obj, smethod, mth) - if not mth.__doc__: - mth.__doc__ = getattr( - getattr(AbstractFileSystem, smethod, None), "__doc__", "" - ) - - -class FSSpecCoroutineCancel(Exception): - pass - - -def _dump_running_tasks( - printout=True, cancel=True, exc=FSSpecCoroutineCancel, with_task=False -): - import traceback - - tasks = [t for t in asyncio.tasks.all_tasks(loop[0]) if not t.done()] - if printout: - [task.print_stack() for task in tasks] - out = [ - { - "locals": task._coro.cr_frame.f_locals, - "file": task._coro.cr_frame.f_code.co_filename, - "firstline": task._coro.cr_frame.f_code.co_firstlineno, - "linelo": task._coro.cr_frame.f_lineno, - "stack": traceback.format_stack(task._coro.cr_frame), - "task": task if with_task else None, - } - for task in tasks - ] - if cancel: - for t in tasks: - cbs = t._callbacks - t.cancel() - asyncio.futures.Future.set_exception(t, exc) - asyncio.futures.Future.cancel(t) - [cb[0](t) for cb in cbs] # cancels any dependent concurrent.futures - try: - t._coro.throw(exc) # exits coro, unless explicitly handled - except exc: - pass - return out - - -class AbstractAsyncStreamedFile(AbstractBufferedFile): - # no read buffering, and always auto-commit - # TODO: readahead might still be useful here, but needs async version - - async def read(self, length=-1): - """ - Return data from cache, or fetch pieces as necessary - - Parameters - ---------- - length: int (-1) - Number of bytes to read; if <0, all remaining bytes. - """ - length = -1 if length is None else int(length) - if self.mode != "rb": - raise ValueError("File not in read mode") - if length < 0: - length = self.size - self.loc - if self.closed: - raise ValueError("I/O operation on closed file.") - if length == 0: - # don't even bother calling fetch - return b"" - out = await self._fetch_range(self.loc, self.loc + length) - self.loc += len(out) - return out - - async def write(self, data): - """ - Write data to buffer. - - Buffer only sent on flush() or if buffer is greater than - or equal to blocksize. - - Parameters - ---------- - data: bytes - Set of bytes to be written. - """ - if self.mode not in {"wb", "ab"}: - raise ValueError("File not in write mode") - if self.closed: - raise ValueError("I/O operation on closed file.") - if self.forced: - raise ValueError("This file has been force-flushed, can only close") - out = self.buffer.write(data) - self.loc += out - if self.buffer.tell() >= self.blocksize: - await self.flush() - return out - - async def close(self): - """Close file - - Finalizes writes, discards cache - """ - if getattr(self, "_unclosable", False): - return - if self.closed: - return - if self.mode == "rb": - self.cache = None - else: - if not self.forced: - await self.flush(force=True) - - if self.fs is not None: - self.fs.invalidate_cache(self.path) - self.fs.invalidate_cache(self.fs._parent(self.path)) - - self.closed = True - - async def flush(self, force=False): - if self.closed: - raise ValueError("Flush on closed file") - if force and self.forced: - raise ValueError("Force flush cannot be called more than once") - if force: - self.forced = True - - if self.mode not in {"wb", "ab"}: - # no-op to flush on read-mode - return - - if not force and self.buffer.tell() < self.blocksize: - # Defer write on small block - return - - if self.offset is None: - # Initialize a multipart upload - self.offset = 0 - try: - await self._initiate_upload() - except: - self.closed = True - raise - - if await self._upload_chunk(final=force) is not False: - self.offset += self.buffer.seek(0, 2) - self.buffer = io.BytesIO() - - async def __aenter__(self): - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb): - await self.close() - - async def _fetch_range(self, start, end): - raise NotImplementedError - - async def _initiate_upload(self): - pass - - async def _upload_chunk(self, final=False): - raise NotImplementedError diff --git a/venv/lib/python3.10/site-packages/fsspec/caching.py b/venv/lib/python3.10/site-packages/fsspec/caching.py deleted file mode 100644 index 9b49d7f5e236c11f6ff625721d02e8ab42086a7f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/caching.py +++ /dev/null @@ -1,1004 +0,0 @@ -from __future__ import annotations - -import collections -import functools -import logging -import math -import os -import threading -from collections import OrderedDict -from collections.abc import Callable -from concurrent.futures import Future, ThreadPoolExecutor -from itertools import groupby -from operator import itemgetter -from typing import TYPE_CHECKING, Any, ClassVar, Generic, NamedTuple, TypeVar - -if TYPE_CHECKING: - import mmap - - from typing_extensions import ParamSpec - - P = ParamSpec("P") -else: - P = TypeVar("P") - -T = TypeVar("T") - - -logger = logging.getLogger("fsspec.caching") - -Fetcher = Callable[[int, int], bytes] # Maps (start, end) to bytes -MultiFetcher = Callable[[list[int, int]], bytes] # Maps [(start, end)] to bytes - - -class BaseCache: - """Pass-though cache: doesn't keep anything, calls every time - - Acts as base class for other cachers - - Parameters - ---------- - blocksize: int - How far to read ahead in numbers of bytes - fetcher: func - Function of the form f(start, end) which gets bytes from remote as - specified - size: int - How big this file is - """ - - name: ClassVar[str] = "none" - - def __init__(self, blocksize: int, fetcher: Fetcher, size: int) -> None: - self.blocksize = blocksize - self.nblocks = 0 - self.fetcher = fetcher - self.size = size - self.hit_count = 0 - self.miss_count = 0 - # the bytes that we actually requested - self.total_requested_bytes = 0 - - def _fetch(self, start: int | None, stop: int | None) -> bytes: - if start is None: - start = 0 - if stop is None: - stop = self.size - if start >= self.size or start >= stop: - return b"" - return self.fetcher(start, stop) - - def _reset_stats(self) -> None: - """Reset hit and miss counts for a more ganular report e.g. by file.""" - self.hit_count = 0 - self.miss_count = 0 - self.total_requested_bytes = 0 - - def _log_stats(self) -> str: - """Return a formatted string of the cache statistics.""" - if self.hit_count == 0 and self.miss_count == 0: - # a cache that does nothing, this is for logs only - return "" - return f" , {self.name}: {self.hit_count} hits, {self.miss_count} misses, {self.total_requested_bytes} total requested bytes" - - def __repr__(self) -> str: - # TODO: use rich for better formatting - return f""" - <{self.__class__.__name__}: - block size : {self.blocksize} - block count : {self.nblocks} - file size : {self.size} - cache hits : {self.hit_count} - cache misses: {self.miss_count} - total requested bytes: {self.total_requested_bytes}> - """ - - -class MMapCache(BaseCache): - """memory-mapped sparse file cache - - Opens temporary file, which is filled blocks-wise when data is requested. - Ensure there is enough disc space in the temporary location. - - This cache method might only work on posix - - Parameters - ---------- - blocksize: int - How far to read ahead in numbers of bytes - fetcher: Fetcher - Function of the form f(start, end) which gets bytes from remote as - specified - size: int - How big this file is - location: str - Where to create the temporary file. If None, a temporary file is - created using tempfile.TemporaryFile(). - blocks: set[int] - Set of block numbers that have already been fetched. If None, an empty - set is created. - multi_fetcher: MultiFetcher - Function of the form f([(start, end)]) which gets bytes from remote - as specified. This function is used to fetch multiple blocks at once. - If not specified, the fetcher function is used instead. - """ - - name = "mmap" - - def __init__( - self, - blocksize: int, - fetcher: Fetcher, - size: int, - location: str | None = None, - blocks: set[int] | None = None, - multi_fetcher: MultiFetcher | None = None, - ) -> None: - super().__init__(blocksize, fetcher, size) - self.blocks = set() if blocks is None else blocks - self.location = location - self.multi_fetcher = multi_fetcher - self.cache = self._makefile() - - def _makefile(self) -> mmap.mmap | bytearray: - import mmap - import tempfile - - if self.size == 0: - return bytearray() - - # posix version - if self.location is None or not os.path.exists(self.location): - if self.location is None: - fd = tempfile.TemporaryFile() - self.blocks = set() - else: - fd = open(self.location, "wb+") - fd.seek(self.size - 1) - fd.write(b"1") - fd.flush() - else: - fd = open(self.location, "r+b") - - return mmap.mmap(fd.fileno(), self.size) - - def _fetch(self, start: int | None, end: int | None) -> bytes: - logger.debug(f"MMap cache fetching {start}-{end}") - if start is None: - start = 0 - if end is None: - end = self.size - if start >= self.size or start >= end: - return b"" - start_block = start // self.blocksize - end_block = end // self.blocksize - block_range = range(start_block, end_block + 1) - # Determine which blocks need to be fetched. This sequence is sorted by construction. - need = (i for i in block_range if i not in self.blocks) - # Count the number of blocks already cached - self.hit_count += sum(1 for i in block_range if i in self.blocks) - - ranges = [] - - # Consolidate needed blocks. - # Algorithm adapted from Python 2.x itertools documentation. - # We are grouping an enumerated sequence of blocks. By comparing when the difference - # between an ascending range (provided by enumerate) and the needed block numbers - # we can detect when the block number skips values. The key computes this difference. - # Whenever the difference changes, we know that we have previously cached block(s), - # and a new group is started. In other words, this algorithm neatly groups - # runs of consecutive block numbers so they can be fetched together. - for _, _blocks in groupby(enumerate(need), key=lambda x: x[0] - x[1]): - # Extract the blocks from the enumerated sequence - _blocks = tuple(map(itemgetter(1), _blocks)) - # Compute start of first block - sstart = _blocks[0] * self.blocksize - # Compute the end of the last block. Last block may not be full size. - send = min(_blocks[-1] * self.blocksize + self.blocksize, self.size) - - # Fetch bytes (could be multiple consecutive blocks) - self.total_requested_bytes += send - sstart - logger.debug( - f"MMap get blocks {_blocks[0]}-{_blocks[-1]} ({sstart}-{send})" - ) - ranges.append((sstart, send)) - - # Update set of cached blocks - self.blocks.update(_blocks) - # Update cache statistics with number of blocks we had to cache - self.miss_count += len(_blocks) - - if not ranges: - return self.cache[start:end] - - if self.multi_fetcher: - logger.debug(f"MMap get blocks {ranges}") - for idx, r in enumerate(self.multi_fetcher(ranges)): - sstart, send = ranges[idx] - logger.debug(f"MMap copy block ({sstart}-{send}") - self.cache[sstart:send] = r - else: - for sstart, send in ranges: - logger.debug(f"MMap get block ({sstart}-{send}") - self.cache[sstart:send] = self.fetcher(sstart, send) - - return self.cache[start:end] - - def __getstate__(self) -> dict[str, Any]: - state = self.__dict__.copy() - # Remove the unpicklable entries. - del state["cache"] - return state - - def __setstate__(self, state: dict[str, Any]) -> None: - # Restore instance attributes - self.__dict__.update(state) - self.cache = self._makefile() - - -class ReadAheadCache(BaseCache): - """Cache which reads only when we get beyond a block of data - - This is a much simpler version of BytesCache, and does not attempt to - fill holes in the cache or keep fragments alive. It is best suited to - many small reads in a sequential order (e.g., reading lines from a file). - """ - - name = "readahead" - - def __init__(self, blocksize: int, fetcher: Fetcher, size: int) -> None: - super().__init__(blocksize, fetcher, size) - self.cache = b"" - self.start = 0 - self.end = 0 - - def _fetch(self, start: int | None, end: int | None) -> bytes: - if start is None: - start = 0 - if end is None or end > self.size: - end = self.size - if start >= self.size or start >= end: - return b"" - l = end - start - if start >= self.start and end <= self.end: - # cache hit - self.hit_count += 1 - return self.cache[start - self.start : end - self.start] - elif self.start <= start < self.end: - # partial hit - self.miss_count += 1 - part = self.cache[start - self.start :] - l -= len(part) - start = self.end - else: - # miss - self.miss_count += 1 - part = b"" - end = min(self.size, end + self.blocksize) - self.total_requested_bytes += end - start - self.cache = self.fetcher(start, end) # new block replaces old - self.start = start - self.end = self.start + len(self.cache) - return part + self.cache[:l] - - -class FirstChunkCache(BaseCache): - """Caches the first block of a file only - - This may be useful for file types where the metadata is stored in the header, - but is randomly accessed. - """ - - name = "first" - - def __init__(self, blocksize: int, fetcher: Fetcher, size: int) -> None: - if blocksize > size: - # this will buffer the whole thing - blocksize = size - super().__init__(blocksize, fetcher, size) - self.cache: bytes | None = None - - def _fetch(self, start: int | None, end: int | None) -> bytes: - start = start or 0 - if start > self.size: - logger.debug("FirstChunkCache: requested start > file size") - return b"" - - end = min(end, self.size) - - if start < self.blocksize: - if self.cache is None: - self.miss_count += 1 - if end > self.blocksize: - self.total_requested_bytes += end - data = self.fetcher(0, end) - self.cache = data[: self.blocksize] - return data[start:] - self.cache = self.fetcher(0, self.blocksize) - self.total_requested_bytes += self.blocksize - part = self.cache[start:end] - if end > self.blocksize: - self.total_requested_bytes += end - self.blocksize - part += self.fetcher(self.blocksize, end) - self.hit_count += 1 - return part - else: - self.miss_count += 1 - self.total_requested_bytes += end - start - return self.fetcher(start, end) - - -class BlockCache(BaseCache): - """ - Cache holding memory as a set of blocks. - - Requests are only ever made ``blocksize`` at a time, and are - stored in an LRU cache. The least recently accessed block is - discarded when more than ``maxblocks`` are stored. - - Parameters - ---------- - blocksize : int - The number of bytes to store in each block. - Requests are only ever made for ``blocksize``, so this - should balance the overhead of making a request against - the granularity of the blocks. - fetcher : Callable - size : int - The total size of the file being cached. - maxblocks : int - The maximum number of blocks to cache for. The maximum memory - use for this cache is then ``blocksize * maxblocks``. - """ - - name = "blockcache" - - def __init__( - self, blocksize: int, fetcher: Fetcher, size: int, maxblocks: int = 32 - ) -> None: - super().__init__(blocksize, fetcher, size) - self.nblocks = math.ceil(size / blocksize) - self.maxblocks = maxblocks - self._fetch_block_cached = functools.lru_cache(maxblocks)(self._fetch_block) - - def cache_info(self): - """ - The statistics on the block cache. - - Returns - ------- - NamedTuple - Returned directly from the LRU Cache used internally. - """ - return self._fetch_block_cached.cache_info() - - def __getstate__(self) -> dict[str, Any]: - state = self.__dict__ - del state["_fetch_block_cached"] - return state - - def __setstate__(self, state: dict[str, Any]) -> None: - self.__dict__.update(state) - self._fetch_block_cached = functools.lru_cache(state["maxblocks"])( - self._fetch_block - ) - - def _fetch(self, start: int | None, end: int | None) -> bytes: - if start is None: - start = 0 - if end is None: - end = self.size - if start >= self.size or start >= end: - return b"" - - return self._read_cache( - start, end, start // self.blocksize, (end - 1) // self.blocksize - ) - - def _fetch_block(self, block_number: int) -> bytes: - """ - Fetch the block of data for `block_number`. - """ - if block_number > self.nblocks: - raise ValueError( - f"'block_number={block_number}' is greater than " - f"the number of blocks ({self.nblocks})" - ) - - start = block_number * self.blocksize - end = start + self.blocksize - self.total_requested_bytes += end - start - self.miss_count += 1 - logger.info("BlockCache fetching block %d", block_number) - block_contents = super()._fetch(start, end) - return block_contents - - def _read_cache( - self, start: int, end: int, start_block_number: int, end_block_number: int - ) -> bytes: - """ - Read from our block cache. - - Parameters - ---------- - start, end : int - The start and end byte positions. - start_block_number, end_block_number : int - The start and end block numbers. - """ - start_pos = start % self.blocksize - end_pos = end % self.blocksize - if end_pos == 0: - end_pos = self.blocksize - - self.hit_count += 1 - if start_block_number == end_block_number: - block: bytes = self._fetch_block_cached(start_block_number) - return block[start_pos:end_pos] - - else: - # read from the initial - out = [self._fetch_block_cached(start_block_number)[start_pos:]] - - # intermediate blocks - # Note: it'd be nice to combine these into one big request. However - # that doesn't play nicely with our LRU cache. - out.extend( - map( - self._fetch_block_cached, - range(start_block_number + 1, end_block_number), - ) - ) - - # final block - out.append(self._fetch_block_cached(end_block_number)[:end_pos]) - - return b"".join(out) - - -class BytesCache(BaseCache): - """Cache which holds data in a in-memory bytes object - - Implements read-ahead by the block size, for semi-random reads progressing - through the file. - - Parameters - ---------- - trim: bool - As we read more data, whether to discard the start of the buffer when - we are more than a blocksize ahead of it. - """ - - name: ClassVar[str] = "bytes" - - def __init__( - self, blocksize: int, fetcher: Fetcher, size: int, trim: bool = True - ) -> None: - super().__init__(blocksize, fetcher, size) - self.cache = b"" - self.start: int | None = None - self.end: int | None = None - self.trim = trim - - def _fetch(self, start: int | None, end: int | None) -> bytes: - # TODO: only set start/end after fetch, in case it fails? - # is this where retry logic might go? - if start is None: - start = 0 - if end is None: - end = self.size - if start >= self.size or start >= end: - return b"" - if ( - self.start is not None - and start >= self.start - and self.end is not None - and end < self.end - ): - # cache hit: we have all the required data - offset = start - self.start - self.hit_count += 1 - return self.cache[offset : offset + end - start] - - if self.blocksize: - bend = min(self.size, end + self.blocksize) - else: - bend = end - - if bend == start or start > self.size: - return b"" - - if (self.start is None or start < self.start) and ( - self.end is None or end > self.end - ): - # First read, or extending both before and after - self.total_requested_bytes += bend - start - self.miss_count += 1 - self.cache = self.fetcher(start, bend) - self.start = start - else: - assert self.start is not None - assert self.end is not None - self.miss_count += 1 - - if start < self.start: - if self.end is None or self.end - end > self.blocksize: - self.total_requested_bytes += bend - start - self.cache = self.fetcher(start, bend) - self.start = start - else: - self.total_requested_bytes += self.start - start - new = self.fetcher(start, self.start) - self.start = start - self.cache = new + self.cache - elif self.end is not None and bend > self.end: - if self.end > self.size: - pass - elif end - self.end > self.blocksize: - self.total_requested_bytes += bend - start - self.cache = self.fetcher(start, bend) - self.start = start - else: - self.total_requested_bytes += bend - self.end - new = self.fetcher(self.end, bend) - self.cache = self.cache + new - - self.end = self.start + len(self.cache) - offset = start - self.start - out = self.cache[offset : offset + end - start] - if self.trim: - num = (self.end - self.start) // (self.blocksize + 1) - if num > 1: - self.start += self.blocksize * num - self.cache = self.cache[self.blocksize * num :] - return out - - def __len__(self) -> int: - return len(self.cache) - - -class AllBytes(BaseCache): - """Cache entire contents of the file""" - - name: ClassVar[str] = "all" - - def __init__( - self, - blocksize: int | None = None, - fetcher: Fetcher | None = None, - size: int | None = None, - data: bytes | None = None, - ) -> None: - super().__init__(blocksize, fetcher, size) # type: ignore[arg-type] - if data is None: - self.miss_count += 1 - self.total_requested_bytes += self.size - data = self.fetcher(0, self.size) - self.data = data - - def _fetch(self, start: int | None, stop: int | None) -> bytes: - self.hit_count += 1 - return self.data[start:stop] - - -class KnownPartsOfAFile(BaseCache): - """ - Cache holding known file parts. - - Parameters - ---------- - blocksize: int - How far to read ahead in numbers of bytes - fetcher: func - Function of the form f(start, end) which gets bytes from remote as - specified - size: int - How big this file is - data: dict - A dictionary mapping explicit `(start, stop)` file-offset tuples - with known bytes. - strict: bool, default True - Whether to fetch reads that go beyond a known byte-range boundary. - If `False`, any read that ends outside a known part will be zero - padded. Note that zero padding will not be used for reads that - begin outside a known byte-range. - """ - - name: ClassVar[str] = "parts" - - def __init__( - self, - blocksize: int, - fetcher: Fetcher, - size: int, - data: dict[tuple[int, int], bytes] | None = None, - strict: bool = False, - **_: Any, - ): - super().__init__(blocksize, fetcher, size) - self.strict = strict - - # simple consolidation of contiguous blocks - if data: - old_offsets = sorted(data.keys()) - offsets = [old_offsets[0]] - blocks = [data.pop(old_offsets[0])] - for start, stop in old_offsets[1:]: - start0, stop0 = offsets[-1] - if start == stop0: - offsets[-1] = (start0, stop) - blocks[-1] += data.pop((start, stop)) - else: - offsets.append((start, stop)) - blocks.append(data.pop((start, stop))) - - self.data = dict(zip(offsets, blocks)) - else: - self.data = {} - - @property - def size(self): - return sum(_[1] - _[0] for _ in self.data) - - @size.setter - def size(self, value): - pass - - @property - def nblocks(self): - return len(self.data) - - @nblocks.setter - def nblocks(self, value): - pass - - def _fetch(self, start: int | None, stop: int | None) -> bytes: - logger.debug("Known parts request %s %s", start, stop) - if start is None: - start = 0 - if stop is None: - stop = self.size - self.total_requested_bytes += stop - start - out = b"" - started = False - loc_old = 0 - for loc0, loc1 in sorted(self.data): - if (loc0 <= start < loc1) and (loc0 <= stop <= loc1): - # entirely within the block - off = start - loc0 - self.hit_count += 1 - return self.data[(loc0, loc1)][off : off + stop - start] - if stop <= loc0: - break - if started and loc0 > loc_old: - # a gap where we need data - self.miss_count += 1 - if self.strict: - raise ValueError - out += b"\x00" * (loc0 - loc_old) - if loc0 <= start < loc1: - # found the start - self.hit_count += 1 - off = start - loc0 - out = self.data[(loc0, loc1)][off : off + stop - start] - started = True - elif start < loc0 and stop > loc1: - # the whole block - self.hit_count += 1 - out += self.data[(loc0, loc1)] - elif loc0 <= stop <= loc1: - # end block - self.hit_count += 1 - out = out + self.data[(loc0, loc1)][: stop - loc0] - return out - loc_old = loc1 - self.miss_count += 1 - if started and not self.strict: - out = out + b"\x00" * (stop - loc_old) - return out - raise ValueError - - -class UpdatableLRU(Generic[P, T]): - """ - Custom implementation of LRU cache that allows updating keys - - Used by BackgroudBlockCache - """ - - class CacheInfo(NamedTuple): - hits: int - misses: int - maxsize: int - currsize: int - - def __init__(self, func: Callable[P, T], max_size: int = 128) -> None: - self._cache: OrderedDict[Any, T] = collections.OrderedDict() - self._func = func - self._max_size = max_size - self._hits = 0 - self._misses = 0 - self._lock = threading.Lock() - - def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: - if kwargs: - raise TypeError(f"Got unexpected keyword argument {kwargs.keys()}") - with self._lock: - if args in self._cache: - self._cache.move_to_end(args) - self._hits += 1 - return self._cache[args] - - result = self._func(*args, **kwargs) - - with self._lock: - self._cache[args] = result - self._misses += 1 - if len(self._cache) > self._max_size: - self._cache.popitem(last=False) - - return result - - def is_key_cached(self, *args: Any) -> bool: - with self._lock: - return args in self._cache - - def add_key(self, result: T, *args: Any) -> None: - with self._lock: - self._cache[args] = result - if len(self._cache) > self._max_size: - self._cache.popitem(last=False) - - def cache_info(self) -> UpdatableLRU.CacheInfo: - with self._lock: - return self.CacheInfo( - maxsize=self._max_size, - currsize=len(self._cache), - hits=self._hits, - misses=self._misses, - ) - - -class BackgroundBlockCache(BaseCache): - """ - Cache holding memory as a set of blocks with pre-loading of - the next block in the background. - - Requests are only ever made ``blocksize`` at a time, and are - stored in an LRU cache. The least recently accessed block is - discarded when more than ``maxblocks`` are stored. If the - next block is not in cache, it is loaded in a separate thread - in non-blocking way. - - Parameters - ---------- - blocksize : int - The number of bytes to store in each block. - Requests are only ever made for ``blocksize``, so this - should balance the overhead of making a request against - the granularity of the blocks. - fetcher : Callable - size : int - The total size of the file being cached. - maxblocks : int - The maximum number of blocks to cache for. The maximum memory - use for this cache is then ``blocksize * maxblocks``. - """ - - name: ClassVar[str] = "background" - - def __init__( - self, blocksize: int, fetcher: Fetcher, size: int, maxblocks: int = 32 - ) -> None: - super().__init__(blocksize, fetcher, size) - self.nblocks = math.ceil(size / blocksize) - self.maxblocks = maxblocks - self._fetch_block_cached = UpdatableLRU(self._fetch_block, maxblocks) - - self._thread_executor = ThreadPoolExecutor(max_workers=1) - self._fetch_future_block_number: int | None = None - self._fetch_future: Future[bytes] | None = None - self._fetch_future_lock = threading.Lock() - - def cache_info(self) -> UpdatableLRU.CacheInfo: - """ - The statistics on the block cache. - - Returns - ------- - NamedTuple - Returned directly from the LRU Cache used internally. - """ - return self._fetch_block_cached.cache_info() - - def __getstate__(self) -> dict[str, Any]: - state = self.__dict__ - del state["_fetch_block_cached"] - del state["_thread_executor"] - del state["_fetch_future_block_number"] - del state["_fetch_future"] - del state["_fetch_future_lock"] - return state - - def __setstate__(self, state) -> None: - self.__dict__.update(state) - self._fetch_block_cached = UpdatableLRU(self._fetch_block, state["maxblocks"]) - self._thread_executor = ThreadPoolExecutor(max_workers=1) - self._fetch_future_block_number = None - self._fetch_future = None - self._fetch_future_lock = threading.Lock() - - def _fetch(self, start: int | None, end: int | None) -> bytes: - if start is None: - start = 0 - if end is None: - end = self.size - if start >= self.size or start >= end: - return b"" - - # byte position -> block numbers - start_block_number = start // self.blocksize - end_block_number = end // self.blocksize - - fetch_future_block_number = None - fetch_future = None - with self._fetch_future_lock: - # Background thread is running. Check we we can or must join it. - if self._fetch_future is not None: - assert self._fetch_future_block_number is not None - if self._fetch_future.done(): - logger.info("BlockCache joined background fetch without waiting.") - self._fetch_block_cached.add_key( - self._fetch_future.result(), self._fetch_future_block_number - ) - # Cleanup the fetch variables. Done with fetching the block. - self._fetch_future_block_number = None - self._fetch_future = None - else: - # Must join if we need the block for the current fetch - must_join = bool( - start_block_number - <= self._fetch_future_block_number - <= end_block_number - ) - if must_join: - # Copy to the local variables to release lock - # before waiting for result - fetch_future_block_number = self._fetch_future_block_number - fetch_future = self._fetch_future - - # Cleanup the fetch variables. Have a local copy. - self._fetch_future_block_number = None - self._fetch_future = None - - # Need to wait for the future for the current read - if fetch_future is not None: - logger.info("BlockCache waiting for background fetch.") - # Wait until result and put it in cache - self._fetch_block_cached.add_key( - fetch_future.result(), fetch_future_block_number - ) - - # these are cached, so safe to do multiple calls for the same start and end. - for block_number in range(start_block_number, end_block_number + 1): - self._fetch_block_cached(block_number) - - # fetch next block in the background if nothing is running in the background, - # the block is within file and it is not already cached - end_block_plus_1 = end_block_number + 1 - with self._fetch_future_lock: - if ( - self._fetch_future is None - and end_block_plus_1 <= self.nblocks - and not self._fetch_block_cached.is_key_cached(end_block_plus_1) - ): - self._fetch_future_block_number = end_block_plus_1 - self._fetch_future = self._thread_executor.submit( - self._fetch_block, end_block_plus_1, "async" - ) - - return self._read_cache( - start, - end, - start_block_number=start_block_number, - end_block_number=end_block_number, - ) - - def _fetch_block(self, block_number: int, log_info: str = "sync") -> bytes: - """ - Fetch the block of data for `block_number`. - """ - if block_number > self.nblocks: - raise ValueError( - f"'block_number={block_number}' is greater than " - f"the number of blocks ({self.nblocks})" - ) - - start = block_number * self.blocksize - end = start + self.blocksize - logger.info("BlockCache fetching block (%s) %d", log_info, block_number) - self.total_requested_bytes += end - start - self.miss_count += 1 - block_contents = super()._fetch(start, end) - return block_contents - - def _read_cache( - self, start: int, end: int, start_block_number: int, end_block_number: int - ) -> bytes: - """ - Read from our block cache. - - Parameters - ---------- - start, end : int - The start and end byte positions. - start_block_number, end_block_number : int - The start and end block numbers. - """ - start_pos = start % self.blocksize - end_pos = end % self.blocksize - - # kind of pointless to count this as a hit, but it is - self.hit_count += 1 - - if start_block_number == end_block_number: - block = self._fetch_block_cached(start_block_number) - return block[start_pos:end_pos] - - else: - # read from the initial - out = [self._fetch_block_cached(start_block_number)[start_pos:]] - - # intermediate blocks - # Note: it'd be nice to combine these into one big request. However - # that doesn't play nicely with our LRU cache. - out.extend( - map( - self._fetch_block_cached, - range(start_block_number + 1, end_block_number), - ) - ) - - # final block - out.append(self._fetch_block_cached(end_block_number)[:end_pos]) - - return b"".join(out) - - -caches: dict[str | None, type[BaseCache]] = { - # one custom case - None: BaseCache, -} - - -def register_cache(cls: type[BaseCache], clobber: bool = False) -> None: - """'Register' cache implementation. - - Parameters - ---------- - clobber: bool, optional - If set to True (default is False) - allow to overwrite existing - entry. - - Raises - ------ - ValueError - """ - name = cls.name - if not clobber and name in caches: - raise ValueError(f"Cache with name {name!r} is already known: {caches[name]}") - caches[name] = cls - - -for c in ( - BaseCache, - MMapCache, - BytesCache, - ReadAheadCache, - BlockCache, - FirstChunkCache, - AllBytes, - KnownPartsOfAFile, - BackgroundBlockCache, -): - register_cache(c) diff --git a/venv/lib/python3.10/site-packages/fsspec/callbacks.py b/venv/lib/python3.10/site-packages/fsspec/callbacks.py deleted file mode 100644 index 7ca99ca6ac3cd69b28bcd1550f6550e8e648c5fe..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/callbacks.py +++ /dev/null @@ -1,324 +0,0 @@ -from functools import wraps - - -class Callback: - """ - Base class and interface for callback mechanism - - This class can be used directly for monitoring file transfers by - providing ``callback=Callback(hooks=...)`` (see the ``hooks`` argument, - below), or subclassed for more specialised behaviour. - - Parameters - ---------- - size: int (optional) - Nominal quantity for the value that corresponds to a complete - transfer, e.g., total number of tiles or total number of - bytes - value: int (0) - Starting internal counter value - hooks: dict or None - A dict of named functions to be called on each update. The signature - of these must be ``f(size, value, **kwargs)`` - """ - - def __init__(self, size=None, value=0, hooks=None, **kwargs): - self.size = size - self.value = value - self.hooks = hooks or {} - self.kw = kwargs - - def __enter__(self): - return self - - def __exit__(self, *exc_args): - self.close() - - def close(self): - """Close callback.""" - - def branched(self, path_1, path_2, **kwargs): - """ - Return callback for child transfers - - If this callback is operating at a higher level, e.g., put, which may - trigger transfers that can also be monitored. The function returns a callback - that has to be passed to the child method, e.g., put_file, - as `callback=` argument. - - The implementation uses `callback.branch` for compatibility. - When implementing callbacks, it is recommended to override this function instead - of `branch` and avoid calling `super().branched(...)`. - - Prefer using this function over `branch`. - - Parameters - ---------- - path_1: str - Child's source path - path_2: str - Child's destination path - **kwargs: - Arbitrary keyword arguments - - Returns - ------- - callback: Callback - A callback instance to be passed to the child method - """ - self.branch(path_1, path_2, kwargs) - # mutate kwargs so that we can force the caller to pass "callback=" explicitly - return kwargs.pop("callback", DEFAULT_CALLBACK) - - def branch_coro(self, fn): - """ - Wraps a coroutine, and pass a new child callback to it. - """ - - @wraps(fn) - async def func(path1, path2: str, **kwargs): - with self.branched(path1, path2, **kwargs) as child: - return await fn(path1, path2, callback=child, **kwargs) - - return func - - def set_size(self, size): - """ - Set the internal maximum size attribute - - Usually called if not initially set at instantiation. Note that this - triggers a ``call()``. - - Parameters - ---------- - size: int - """ - self.size = size - self.call() - - def absolute_update(self, value): - """ - Set the internal value state - - Triggers ``call()`` - - Parameters - ---------- - value: int - """ - self.value = value - self.call() - - def relative_update(self, inc=1): - """ - Delta increment the internal counter - - Triggers ``call()`` - - Parameters - ---------- - inc: int - """ - self.value += inc - self.call() - - def call(self, hook_name=None, **kwargs): - """ - Execute hook(s) with current state - - Each function is passed the internal size and current value - - Parameters - ---------- - hook_name: str or None - If given, execute on this hook - kwargs: passed on to (all) hook(s) - """ - if not self.hooks: - return - kw = self.kw.copy() - kw.update(kwargs) - if hook_name: - if hook_name not in self.hooks: - return - return self.hooks[hook_name](self.size, self.value, **kw) - for hook in self.hooks.values() or []: - hook(self.size, self.value, **kw) - - def wrap(self, iterable): - """ - Wrap an iterable to call ``relative_update`` on each iterations - - Parameters - ---------- - iterable: Iterable - The iterable that is being wrapped - """ - for item in iterable: - self.relative_update() - yield item - - def branch(self, path_1, path_2, kwargs): - """ - Set callbacks for child transfers - - If this callback is operating at a higher level, e.g., put, which may - trigger transfers that can also be monitored. The passed kwargs are - to be *mutated* to add ``callback=``, if this class supports branching - to children. - - Parameters - ---------- - path_1: str - Child's source path - path_2: str - Child's destination path - kwargs: dict - arguments passed to child method, e.g., put_file. - - Returns - ------- - - """ - return None - - def no_op(self, *_, **__): - pass - - def __getattr__(self, item): - """ - If undefined methods are called on this class, nothing happens - """ - return self.no_op - - @classmethod - def as_callback(cls, maybe_callback=None): - """Transform callback=... into Callback instance - - For the special value of ``None``, return the global instance of - ``NoOpCallback``. This is an alternative to including - ``callback=DEFAULT_CALLBACK`` directly in a method signature. - """ - if maybe_callback is None: - return DEFAULT_CALLBACK - return maybe_callback - - -class NoOpCallback(Callback): - """ - This implementation of Callback does exactly nothing - """ - - def call(self, *args, **kwargs): - return None - - -class DotPrinterCallback(Callback): - """ - Simple example Callback implementation - - Almost identical to Callback with a hook that prints a char; here we - demonstrate how the outer layer may print "#" and the inner layer "." - """ - - def __init__(self, chr_to_print="#", **kwargs): - self.chr = chr_to_print - super().__init__(**kwargs) - - def branch(self, path_1, path_2, kwargs): - """Mutate kwargs to add new instance with different print char""" - kwargs["callback"] = DotPrinterCallback(".") - - def call(self, **kwargs): - """Just outputs a character""" - print(self.chr, end="") - - -class TqdmCallback(Callback): - """ - A callback to display a progress bar using tqdm - - Parameters - ---------- - tqdm_kwargs : dict, (optional) - Any argument accepted by the tqdm constructor. - See the `tqdm doc `_. - Will be forwarded to `tqdm_cls`. - tqdm_cls: (optional) - subclass of `tqdm.tqdm`. If not passed, it will default to `tqdm.tqdm`. - - Examples - -------- - >>> import fsspec - >>> from fsspec.callbacks import TqdmCallback - >>> fs = fsspec.filesystem("memory") - >>> path2distant_data = "/your-path" - >>> fs.upload( - ".", - path2distant_data, - recursive=True, - callback=TqdmCallback(), - ) - - You can forward args to tqdm using the ``tqdm_kwargs`` parameter. - - >>> fs.upload( - ".", - path2distant_data, - recursive=True, - callback=TqdmCallback(tqdm_kwargs={"desc": "Your tqdm description"}), - ) - - You can also customize the progress bar by passing a subclass of `tqdm`. - - .. code-block:: python - - class TqdmFormat(tqdm): - '''Provides a `total_time` format parameter''' - @property - def format_dict(self): - d = super().format_dict - total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1) - d.update(total_time=self.format_interval(total_time) + " in total") - return d - - >>> with TqdmCallback( - tqdm_kwargs={ - "desc": "desc", - "bar_format": "{total_time}: {percentage:.0f}%|{bar}{r_bar}", - }, - tqdm_cls=TqdmFormat, - ) as callback: - fs.upload(".", path2distant_data, recursive=True, callback=callback) - """ - - def __init__(self, tqdm_kwargs=None, *args, **kwargs): - try: - from tqdm import tqdm - - except ImportError as exce: - raise ImportError( - "Using TqdmCallback requires tqdm to be installed" - ) from exce - - self._tqdm_cls = kwargs.pop("tqdm_cls", tqdm) - self._tqdm_kwargs = tqdm_kwargs or {} - self.tqdm = None - super().__init__(*args, **kwargs) - - def call(self, *args, **kwargs): - if self.tqdm is None: - self.tqdm = self._tqdm_cls(total=self.size, **self._tqdm_kwargs) - self.tqdm.total = self.size - self.tqdm.update(self.value - self.tqdm.n) - - def close(self): - if self.tqdm is not None: - self.tqdm.close() - self.tqdm = None - - def __del__(self): - return self.close() - - -DEFAULT_CALLBACK = _DEFAULT_CALLBACK = NoOpCallback() diff --git a/venv/lib/python3.10/site-packages/fsspec/compression.py b/venv/lib/python3.10/site-packages/fsspec/compression.py deleted file mode 100644 index 11c2e3d3f142d95186663fa5a747911e66832266..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/compression.py +++ /dev/null @@ -1,185 +0,0 @@ -"""Helper functions for a standard streaming compression API""" - -import sys -from zipfile import ZipFile - -import fsspec.utils -from fsspec.spec import AbstractBufferedFile - - -def noop_file(file, mode, **kwargs): - return file - - -# TODO: files should also be available as contexts -# should be functions of the form func(infile, mode=, **kwargs) -> file-like -compr = {None: noop_file} - - -def register_compression(name, callback, extensions, force=False): - """Register an "inferable" file compression type. - - Registers transparent file compression type for use with fsspec.open. - Compression can be specified by name in open, or "infer"-ed for any files - ending with the given extensions. - - Args: - name: (str) The compression type name. Eg. "gzip". - callback: A callable of form (infile, mode, **kwargs) -> file-like. - Accepts an input file-like object, the target mode and kwargs. - Returns a wrapped file-like object. - extensions: (str, Iterable[str]) A file extension, or list of file - extensions for which to infer this compression scheme. Eg. "gz". - force: (bool) Force re-registration of compression type or extensions. - - Raises: - ValueError: If name or extensions already registered, and not force. - - """ - if isinstance(extensions, str): - extensions = [extensions] - - # Validate registration - if name in compr and not force: - raise ValueError(f"Duplicate compression registration: {name}") - - for ext in extensions: - if ext in fsspec.utils.compressions and not force: - raise ValueError(f"Duplicate compression file extension: {ext} ({name})") - - compr[name] = callback - - for ext in extensions: - fsspec.utils.compressions[ext] = name - - -def unzip(infile, mode="rb", filename=None, **kwargs): - if "r" not in mode: - filename = filename or "file" - z = ZipFile(infile, mode="w", **kwargs) - fo = z.open(filename, mode="w") - fo.close = lambda closer=fo.close: closer() or z.close() - return fo - z = ZipFile(infile) - if filename is None: - filename = z.namelist()[0] - return z.open(filename, mode="r", **kwargs) - - -register_compression("zip", unzip, "zip") - -try: - from bz2 import BZ2File -except ImportError: - pass -else: - register_compression("bz2", BZ2File, "bz2") - -try: # pragma: no cover - from isal import igzip - - def isal(infile, mode="rb", **kwargs): - return igzip.IGzipFile(fileobj=infile, mode=mode, **kwargs) - - register_compression("gzip", isal, "gz") -except ImportError: - from gzip import GzipFile - - register_compression( - "gzip", lambda f, **kwargs: GzipFile(fileobj=f, **kwargs), "gz" - ) - -try: - from lzma import LZMAFile - - register_compression("lzma", LZMAFile, "lzma") - register_compression("xz", LZMAFile, "xz") -except ImportError: - pass - -try: - import lzmaffi - - register_compression("lzma", lzmaffi.LZMAFile, "lzma", force=True) - register_compression("xz", lzmaffi.LZMAFile, "xz", force=True) -except ImportError: - pass - - -class SnappyFile(AbstractBufferedFile): - def __init__(self, infile, mode, **kwargs): - import snappy - - super().__init__( - fs=None, path="snappy", mode=mode.strip("b") + "b", size=999999999, **kwargs - ) - self.infile = infile - if "r" in mode: - self.codec = snappy.StreamDecompressor() - else: - self.codec = snappy.StreamCompressor() - - def _upload_chunk(self, final=False): - self.buffer.seek(0) - out = self.codec.add_chunk(self.buffer.read()) - self.infile.write(out) - return True - - def seek(self, loc, whence=0): - raise NotImplementedError("SnappyFile is not seekable") - - def seekable(self): - return False - - def _fetch_range(self, start, end): - """Get the specified set of bytes from remote""" - data = self.infile.read(end - start) - return self.codec.decompress(data) - - -try: - import snappy - - snappy.compress(b"") - # Snappy may use the .sz file extension, but this is not part of the - # standard implementation. - register_compression("snappy", SnappyFile, []) - -except (ImportError, NameError, AttributeError): - pass - -try: - import lz4.frame - - register_compression("lz4", lz4.frame.open, "lz4") -except ImportError: - pass - -try: - if sys.version_info >= (3, 14): - from compression import zstd - else: - from backports import zstd - - register_compression("zstd", zstd.ZstdFile, "zst") -except ImportError: - try: - import zstandard as zstd - - def zstandard_file(infile, mode="rb"): - if "r" in mode: - cctx = zstd.ZstdDecompressor() - return cctx.stream_reader(infile) - else: - cctx = zstd.ZstdCompressor(level=10) - return cctx.stream_writer(infile) - - register_compression("zstd", zstandard_file, "zst") - except ImportError: - pass - pass - - -def available_compressions(): - """Return a list of the implemented compressions.""" - return list(compr) diff --git a/venv/lib/python3.10/site-packages/fsspec/config.py b/venv/lib/python3.10/site-packages/fsspec/config.py deleted file mode 100644 index 76d9af14aaf7df47c4551c169f27b05abf9c269e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/config.py +++ /dev/null @@ -1,131 +0,0 @@ -from __future__ import annotations - -import configparser -import json -import os -import warnings -from typing import Any - -conf: dict[str, dict[str, Any]] = {} -default_conf_dir = os.path.join(os.path.expanduser("~"), ".config/fsspec") -conf_dir = os.environ.get("FSSPEC_CONFIG_DIR", default_conf_dir) - - -def set_conf_env(conf_dict, envdict=os.environ): - """Set config values from environment variables - - Looks for variables of the form ``FSSPEC_`` and - ``FSSPEC__``. For ``FSSPEC_`` the value is parsed - as a json dictionary and used to ``update`` the config of the - corresponding protocol. For ``FSSPEC__`` there is no - attempt to convert the string value, but the kwarg keys will be lower-cased. - - The ``FSSPEC__`` variables are applied after the - ``FSSPEC_`` ones. - - Parameters - ---------- - conf_dict : dict(str, dict) - This dict will be mutated - envdict : dict-like(str, str) - Source for the values - usually the real environment - """ - kwarg_keys = [] - for key in envdict: - if key.startswith("FSSPEC_") and len(key) > 7 and key[7] != "_": - if key.count("_") > 1: - kwarg_keys.append(key) - continue - try: - value = json.loads(envdict[key]) - except json.decoder.JSONDecodeError as ex: - warnings.warn( - f"Ignoring environment variable {key} due to a parse failure: {ex}" - ) - else: - if isinstance(value, dict): - _, proto = key.split("_", 1) - conf_dict.setdefault(proto.lower(), {}).update(value) - else: - warnings.warn( - f"Ignoring environment variable {key} due to not being a dict:" - f" {type(value)}" - ) - elif key.startswith("FSSPEC"): - warnings.warn( - f"Ignoring environment variable {key} due to having an unexpected name" - ) - - for key in kwarg_keys: - _, proto, kwarg = key.split("_", 2) - conf_dict.setdefault(proto.lower(), {})[kwarg.lower()] = envdict[key] - - -def set_conf_files(cdir, conf_dict): - """Set config values from files - - Scans for INI and JSON files in the given dictionary, and uses their - contents to set the config. In case of repeated values, later values - win. - - In the case of INI files, all values are strings, and these will not - be converted. - - Parameters - ---------- - cdir : str - Directory to search - conf_dict : dict(str, dict) - This dict will be mutated - """ - if not os.path.isdir(cdir): - return - allfiles = sorted(os.listdir(cdir)) - for fn in allfiles: - if fn.endswith(".ini"): - ini = configparser.ConfigParser() - ini.read(os.path.join(cdir, fn)) - for key in ini: - if key == "DEFAULT": - continue - conf_dict.setdefault(key, {}).update(dict(ini[key])) - if fn.endswith(".json"): - with open(os.path.join(cdir, fn)) as f: - js = json.load(f) - for key in js: - conf_dict.setdefault(key, {}).update(dict(js[key])) - - -def apply_config(cls, kwargs, conf_dict=None): - """Supply default values for kwargs when instantiating class - - Augments the passed kwargs, by finding entries in the config dict - which match the classes ``.protocol`` attribute (one or more str) - - Parameters - ---------- - cls : file system implementation - kwargs : dict - conf_dict : dict of dict - Typically this is the global configuration - - Returns - ------- - dict : the modified set of kwargs - """ - if conf_dict is None: - conf_dict = conf - protos = cls.protocol if isinstance(cls.protocol, (tuple, list)) else [cls.protocol] - kw = {} - for proto in protos: - # default kwargs from the current state of the config - if proto in conf_dict: - kw.update(conf_dict[proto]) - # explicit kwargs always win - kw.update(**kwargs) - kwargs = kw - return kwargs - - -set_conf_files(conf_dir, conf) -set_conf_env(conf) diff --git a/venv/lib/python3.10/site-packages/fsspec/conftest.py b/venv/lib/python3.10/site-packages/fsspec/conftest.py deleted file mode 100644 index f05eb5c30d42b0c1c5cc432f9c217d8f0e01f412..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/conftest.py +++ /dev/null @@ -1,125 +0,0 @@ -import os -import shutil -import subprocess -import sys -import time -from collections import deque -from collections.abc import Generator, Sequence - -import pytest - -import fsspec - - -@pytest.fixture() -def m(): - """ - Fixture providing a memory filesystem. - """ - m = fsspec.filesystem("memory") - m.store.clear() - m.pseudo_dirs.clear() - m.pseudo_dirs.append("") - try: - yield m - finally: - m.store.clear() - m.pseudo_dirs.clear() - m.pseudo_dirs.append("") - - -class InstanceCacheInspector: - """ - Helper class to inspect instance caches of filesystem classes in tests. - """ - - def clear(self) -> None: - """ - Clear instance caches of all currently imported filesystem classes. - """ - classes = deque([fsspec.spec.AbstractFileSystem]) - while classes: - cls = classes.popleft() - cls.clear_instance_cache() - classes.extend(cls.__subclasses__()) - - def gather_counts(self, *, omit_zero: bool = True) -> dict[str, int]: - """ - Gather counts of filesystem instances in the instance caches - of all currently imported filesystem classes. - - Parameters - ---------- - omit_zero: - Whether to omit instance types with no cached instances. - """ - out: dict[str, int] = {} - classes = deque([fsspec.spec.AbstractFileSystem]) - while classes: - cls = classes.popleft() - count = len(cls._cache) # there is no public interface for the cache - # note: skip intermediate AbstractFileSystem subclasses - # if they proxy the protocol attribute via a property. - if isinstance(cls.protocol, (Sequence, str)): - key = cls.protocol if isinstance(cls.protocol, str) else cls.protocol[0] - if count or not omit_zero: - out[key] = count - classes.extend(cls.__subclasses__()) - return out - - -@pytest.fixture(scope="function", autouse=True) -def instance_caches() -> Generator[InstanceCacheInspector, None, None]: - """ - Fixture to ensure empty filesystem instance caches before and after a test. - - Used by default for all tests. - Clears caches of all imported filesystem classes. - Can be used to write test assertions about instance caches. - - Usage: - - def test_something(instance_caches): - # Test code here - fsspec.open("file://abc") - fsspec.open("memory://foo/bar") - - # Test assertion - assert instance_caches.gather_counts() == {"file": 1, "memory": 1} - - Returns - ------- - instance_caches: An instance cache inspector for clearing and inspecting caches. - """ - ic = InstanceCacheInspector() - - ic.clear() - try: - yield ic - finally: - ic.clear() - - -@pytest.fixture(scope="function") -def ftp_writable(tmpdir): - """ - Fixture providing a writable FTP filesystem. - """ - pytest.importorskip("pyftpdlib") - - d = str(tmpdir) - with open(os.path.join(d, "out"), "wb") as f: - f.write(b"hello" * 10000) - P = subprocess.Popen( - [sys.executable, "-m", "pyftpdlib", "-d", d, "-u", "user", "-P", "pass", "-w"] - ) - try: - time.sleep(1) - yield "localhost", 2121, "user", "pass" - finally: - P.terminate() - P.wait() - try: - shutil.rmtree(tmpdir) - except Exception: - pass diff --git a/venv/lib/python3.10/site-packages/fsspec/core.py b/venv/lib/python3.10/site-packages/fsspec/core.py deleted file mode 100644 index 5876bfcefc176b3b3aed0e16b54fa3809a5a0eee..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/core.py +++ /dev/null @@ -1,760 +0,0 @@ -from __future__ import annotations - -import io -import logging -import os -import re -from glob import has_magic -from pathlib import Path - -# for backwards compat, we export cache things from here too -from fsspec.caching import ( # noqa: F401 - BaseCache, - BlockCache, - BytesCache, - MMapCache, - ReadAheadCache, - caches, -) -from fsspec.compression import compr -from fsspec.config import conf -from fsspec.registry import available_protocols, filesystem, get_filesystem_class -from fsspec.utils import ( - _unstrip_protocol, - build_name_function, - infer_compression, - stringify_path, -) - -logger = logging.getLogger("fsspec") - - -class OpenFile: - """ - File-like object to be used in a context - - Can layer (buffered) text-mode and compression over any file-system, which - are typically binary-only. - - These instances are safe to serialize, as the low-level file object - is not created until invoked using ``with``. - - Parameters - ---------- - fs: FileSystem - The file system to use for opening the file. Should be a subclass or duck-type - with ``fsspec.spec.AbstractFileSystem`` - path: str - Location to open - mode: str like 'rb', optional - Mode of the opened file - compression: str or None, optional - Compression to apply - encoding: str or None, optional - The encoding to use if opened in text mode. - errors: str or None, optional - How to handle encoding errors if opened in text mode. - newline: None or str - Passed to TextIOWrapper in text mode, how to handle line endings. - autoopen: bool - If True, calls open() immediately. Mostly used by pickle - pos: int - If given and autoopen is True, seek to this location immediately - """ - - def __init__( - self, - fs, - path, - mode="rb", - compression=None, - encoding=None, - errors=None, - newline=None, - ): - self.fs = fs - self.path = path - self.mode = mode - self.compression = get_compression(path, compression) - self.encoding = encoding - self.errors = errors - self.newline = newline - self.fobjects = [] - - def __reduce__(self): - return ( - OpenFile, - ( - self.fs, - self.path, - self.mode, - self.compression, - self.encoding, - self.errors, - self.newline, - ), - ) - - def __repr__(self): - return f"" - - def __enter__(self): - mode = self.mode.replace("t", "").replace("b", "") + "b" - - try: - f = self.fs.open(self.path, mode=mode) - except FileNotFoundError as e: - if has_magic(self.path): - raise FileNotFoundError( - "%s not found. The URL contains glob characters: you maybe needed\n" - "to pass expand=True in fsspec.open() or the storage_options of \n" - "your library. You can also set the config value 'open_expand'\n" - "before import, or fsspec.core.DEFAULT_EXPAND at runtime, to True.", - self.path, - ) from e - raise - - self.fobjects = [f] - - if self.compression is not None: - compress = compr[self.compression] - f = compress(f, mode=mode[0]) - self.fobjects.append(f) - - if "b" not in self.mode: - # assume, for example, that 'r' is equivalent to 'rt' as in builtin - f = PickleableTextIOWrapper( - f, encoding=self.encoding, errors=self.errors, newline=self.newline - ) - self.fobjects.append(f) - - return self.fobjects[-1] - - def __exit__(self, *args): - self.close() - - @property - def full_name(self): - return _unstrip_protocol(self.path, self.fs) - - def open(self): - """Materialise this as a real open file without context - - The OpenFile object should be explicitly closed to avoid enclosed file - instances persisting. You must, therefore, keep a reference to the OpenFile - during the life of the file-like it generates. - """ - return self.__enter__() - - def close(self): - """Close all encapsulated file objects""" - for f in reversed(self.fobjects): - if "r" not in self.mode and not f.closed: - f.flush() - f.close() - self.fobjects.clear() - - -class OpenFiles(list): - """List of OpenFile instances - - Can be used in a single context, which opens and closes all of the - contained files. Normal list access to get the elements works as - normal. - - A special case is made for caching filesystems - the files will - be down/uploaded together at the start or end of the context, and - this may happen concurrently, if the target filesystem supports it. - """ - - def __init__(self, *args, mode="rb", fs=None): - self.mode = mode - self.fs = fs - self.files = [] - super().__init__(*args) - - def __enter__(self): - if self.fs is None: - raise ValueError("Context has already been used") - - fs = self.fs - while True: - if hasattr(fs, "open_many"): - # check for concurrent cache download; or set up for upload - self.files = fs.open_many(self) - return self.files - if hasattr(fs, "fs") and fs.fs is not None: - fs = fs.fs - else: - break - return [s.__enter__() for s in self] - - def __exit__(self, *args): - fs = self.fs - [s.__exit__(*args) for s in self] - if "r" not in self.mode: - while True: - if hasattr(fs, "open_many"): - # check for concurrent cache upload - fs.commit_many(self.files) - return - if hasattr(fs, "fs") and fs.fs is not None: - fs = fs.fs - else: - break - - def __getitem__(self, item): - out = super().__getitem__(item) - if isinstance(item, slice): - return OpenFiles(out, mode=self.mode, fs=self.fs) - return out - - def __repr__(self): - return f"" - - -def open_files( - urlpath, - mode="rb", - compression=None, - encoding="utf8", - errors=None, - name_function=None, - num=1, - protocol=None, - newline=None, - auto_mkdir=True, - expand=True, - **kwargs, -): - """Given a path or paths, return a list of ``OpenFile`` objects. - - For writing, a str path must contain the "*" character, which will be filled - in by increasing numbers, e.g., "part*" -> "part1", "part2" if num=2. - - For either reading or writing, can instead provide explicit list of paths. - - Parameters - ---------- - urlpath: string or list - Absolute or relative filepath(s). Prefix with a protocol like ``s3://`` - to read from alternative filesystems. To read from multiple files you - can pass a globstring or a list of paths, with the caveat that they - must all have the same protocol. - mode: 'rb', 'wt', etc. - compression: string or None - If given, open file using compression codec. Can either be a compression - name (a key in ``fsspec.compression.compr``) or "infer" to guess the - compression from the filename suffix. - encoding: str - For text mode only - errors: None or str - Passed to TextIOWrapper in text mode - name_function: function or None - if opening a set of files for writing, those files do not yet exist, - so we need to generate their names by formatting the urlpath for - each sequence number - num: int [1] - if writing mode, number of files we expect to create (passed to - name+function) - protocol: str or None - If given, overrides the protocol found in the URL. - newline: bytes or None - Used for line terminator in text mode. If None, uses system default; - if blank, uses no translation. - auto_mkdir: bool (True) - If in write mode, this will ensure the target directory exists before - writing, by calling ``fs.mkdirs(exist_ok=True)``. - expand: bool - **kwargs: dict - Extra options that make sense to a particular storage connection, e.g. - host, port, username, password, etc. - - Examples - -------- - >>> files = open_files('2015-*-*.csv') # doctest: +SKIP - >>> files = open_files( - ... 's3://bucket/2015-*-*.csv.gz', compression='gzip' - ... ) # doctest: +SKIP - - Returns - ------- - An ``OpenFiles`` instance, which is a list of ``OpenFile`` objects that can - be used as a single context - - Notes - ----- - For a full list of the available protocols and the implementations that - they map across to see the latest online documentation: - - - For implementations built into ``fsspec`` see - https://filesystem-spec.readthedocs.io/en/latest/api.html#built-in-implementations - - For implementations in separate packages see - https://filesystem-spec.readthedocs.io/en/latest/api.html#other-known-implementations - """ - fs, fs_token, paths = get_fs_token_paths( - urlpath, - mode, - num=num, - name_function=name_function, - storage_options=kwargs, - protocol=protocol, - expand=expand, - ) - if fs.protocol == "file": - fs.auto_mkdir = auto_mkdir - elif "r" not in mode and auto_mkdir: - parents = {fs._parent(path) for path in paths} - for parent in parents: - try: - fs.makedirs(parent, exist_ok=True) - except PermissionError: - pass - return OpenFiles( - [ - OpenFile( - fs, - path, - mode=mode, - compression=compression, - encoding=encoding, - errors=errors, - newline=newline, - ) - for path in paths - ], - mode=mode, - fs=fs, - ) - - -def _un_chain(path, kwargs): - # Avoid a circular import - from fsspec.implementations.chained import ChainedFileSystem - - if "::" in path: - x = re.compile(".*[^a-z]+.*") # test for non protocol-like single word - known_protocols = set(available_protocols()) - bits = [] - - # split on '::', then ensure each bit has a protocol - for p in path.split("::"): - if p in known_protocols: - bits.append(p + "://") - elif "://" in p or x.match(p): - bits.append(p) - else: - bits.append(p + "://") - else: - bits = [path] - - # [[url, protocol, kwargs], ...] - out = [] - previous_bit = None - kwargs = kwargs.copy() - - for bit in reversed(bits): - protocol = kwargs.pop("protocol", None) or split_protocol(bit)[0] or "file" - cls = get_filesystem_class(protocol) - extra_kwargs = cls._get_kwargs_from_urls(bit) - kws = kwargs.pop(protocol, {}) - - if bit is bits[0]: - kws.update(kwargs) - - kw = dict( - **{k: v for k, v in extra_kwargs.items() if k not in kws or v != kws[k]}, - **kws, - ) - bit = cls._strip_protocol(bit) - - if ( - "target_protocol" not in kw - and issubclass(cls, ChainedFileSystem) - and not bit - ): - # replace bit if we are chaining and no path given - bit = previous_bit - - out.append((bit, protocol, kw)) - previous_bit = bit - - out.reverse() - return out - - -def url_to_fs(url, **kwargs): - """ - Turn fully-qualified and potentially chained URL into filesystem instance - - Parameters - ---------- - url : str - The fsspec-compatible URL - **kwargs: dict - Extra options that make sense to a particular storage connection, e.g. - host, port, username, password, etc. - - Returns - ------- - filesystem : FileSystem - The new filesystem discovered from ``url`` and created with - ``**kwargs``. - urlpath : str - The file-systems-specific URL for ``url``. - """ - url = stringify_path(url) - # non-FS arguments that appear in fsspec.open() - # inspect could keep this in sync with open()'s signature - known_kwargs = { - "compression", - "encoding", - "errors", - "expand", - "mode", - "name_function", - "newline", - "num", - } - kwargs = {k: v for k, v in kwargs.items() if k not in known_kwargs} - chain = _un_chain(url, kwargs) - inkwargs = {} - # Reverse iterate the chain, creating a nested target_* structure - for i, ch in enumerate(reversed(chain)): - urls, protocol, kw = ch - if i == len(chain) - 1: - inkwargs = dict(**kw, **inkwargs) - continue - inkwargs["target_options"] = dict(**kw, **inkwargs) - inkwargs["target_protocol"] = protocol - inkwargs["fo"] = urls - urlpath, protocol, _ = chain[0] - fs = filesystem(protocol, **inkwargs) - return fs, urlpath - - -DEFAULT_EXPAND = conf.get("open_expand", False) - - -def open( - urlpath, - mode="rb", - compression=None, - encoding="utf8", - errors=None, - protocol=None, - newline=None, - expand=None, - **kwargs, -): - """Given a path or paths, return one ``OpenFile`` object. - - Parameters - ---------- - urlpath: string or list - Absolute or relative filepath. Prefix with a protocol like ``s3://`` - to read from alternative filesystems. Should not include glob - character(s). - mode: 'rb', 'wt', etc. - compression: string or None - If given, open file using compression codec. Can either be a compression - name (a key in ``fsspec.compression.compr``) or "infer" to guess the - compression from the filename suffix. - encoding: str - For text mode only - errors: None or str - Passed to TextIOWrapper in text mode - protocol: str or None - If given, overrides the protocol found in the URL. - newline: bytes or None - Used for line terminator in text mode. If None, uses system default; - if blank, uses no translation. - expand: bool or None - Whether to regard file paths containing special glob characters as needing - expansion (finding the first match) or absolute. Setting False allows using - paths which do embed such characters. If None (default), this argument - takes its value from the DEFAULT_EXPAND module variable, which takes - its initial value from the "open_expand" config value at startup, which will - be False if not set. - **kwargs: dict - Extra options that make sense to a particular storage connection, e.g. - host, port, username, password, etc. - - Examples - -------- - >>> openfile = open('2015-01-01.csv') # doctest: +SKIP - >>> openfile = open( - ... 's3://bucket/2015-01-01.csv.gz', compression='gzip' - ... ) # doctest: +SKIP - >>> with openfile as f: - ... df = pd.read_csv(f) # doctest: +SKIP - ... - - Returns - ------- - ``OpenFile`` object. - - Notes - ----- - For a full list of the available protocols and the implementations that - they map across to see the latest online documentation: - - - For implementations built into ``fsspec`` see - https://filesystem-spec.readthedocs.io/en/latest/api.html#built-in-implementations - - For implementations in separate packages see - https://filesystem-spec.readthedocs.io/en/latest/api.html#other-known-implementations - """ - expand = DEFAULT_EXPAND if expand is None else expand - out = open_files( - urlpath=[urlpath], - mode=mode, - compression=compression, - encoding=encoding, - errors=errors, - protocol=protocol, - newline=newline, - expand=expand, - **kwargs, - ) - if not out: - raise FileNotFoundError(urlpath) - return out[0] - - -def open_local( - url: str | list[str] | Path | list[Path], - mode: str = "rb", - **storage_options: dict, -) -> str | list[str]: - """Open file(s) which can be resolved to local - - For files which either are local, or get downloaded upon open - (e.g., by file caching) - - Parameters - ---------- - url: str or list(str) - mode: str - Must be read mode - storage_options: - passed on to FS for or used by open_files (e.g., compression) - """ - if "r" not in mode: - raise ValueError("Can only ensure local files when reading") - of = open_files(url, mode=mode, **storage_options) - if not getattr(of[0].fs, "local_file", False): - raise ValueError( - "open_local can only be used on a filesystem which" - " has attribute local_file=True" - ) - with of as files: - paths = [f.name for f in files] - if (isinstance(url, str) and not has_magic(url)) or isinstance(url, Path): - return paths[0] - return paths - - -def get_compression(urlpath, compression): - if compression == "infer": - compression = infer_compression(urlpath) - if compression is not None and compression not in compr: - raise ValueError(f"Compression type {compression} not supported") - return compression - - -def split_protocol(urlpath): - """Return protocol, path pair""" - urlpath = stringify_path(urlpath) - if "://" in urlpath: - protocol, path = urlpath.split("://", 1) - if len(protocol) > 1: - # excludes Windows paths - return protocol, path - if urlpath.startswith("data:"): - return urlpath.split(":", 1) - return None, urlpath - - -def strip_protocol(urlpath): - """Return only path part of full URL, according to appropriate backend""" - protocol, _ = split_protocol(urlpath) - cls = get_filesystem_class(protocol) - return cls._strip_protocol(urlpath) - - -def expand_paths_if_needed(paths, mode, num, fs, name_function): - """Expand paths if they have a ``*`` in them (write mode) or any of ``*?[]`` - in them (read mode). - - :param paths: list of paths - mode: str - Mode in which to open files. - num: int - If opening in writing mode, number of files we expect to create. - fs: filesystem object - name_function: callable - If opening in writing mode, this callable is used to generate path - names. Names are generated for each partition by - ``urlpath.replace('*', name_function(partition_index))``. - :return: list of paths - """ - expanded_paths = [] - paths = list(paths) - - if "w" in mode: # read mode - if sum(1 for p in paths if "*" in p) > 1: - raise ValueError( - "When writing data, only one filename mask can be specified." - ) - num = max(num, len(paths)) - - for curr_path in paths: - if "*" in curr_path: - # expand using name_function - expanded_paths.extend(_expand_paths(curr_path, name_function, num)) - else: - expanded_paths.append(curr_path) - # if we generated more paths that asked for, trim the list - if len(expanded_paths) > num: - expanded_paths = expanded_paths[:num] - - else: # read mode - for curr_path in paths: - if has_magic(curr_path): - # expand using glob - expanded_paths.extend(fs.glob(curr_path)) - else: - expanded_paths.append(curr_path) - - return expanded_paths - - -def get_fs_token_paths( - urlpath, - mode="rb", - num=1, - name_function=None, - storage_options=None, - protocol=None, - expand=True, -): - """Filesystem, deterministic token, and paths from a urlpath and options. - - Parameters - ---------- - urlpath: string or iterable - Absolute or relative filepath, URL (may include protocols like - ``s3://``), or globstring pointing to data. - mode: str, optional - Mode in which to open files. - num: int, optional - If opening in writing mode, number of files we expect to create. - name_function: callable, optional - If opening in writing mode, this callable is used to generate path - names. Names are generated for each partition by - ``urlpath.replace('*', name_function(partition_index))``. - storage_options: dict, optional - Additional keywords to pass to the filesystem class. - protocol: str or None - To override the protocol specifier in the URL - expand: bool - Expand string paths for writing, assuming the path is a directory - """ - if isinstance(urlpath, (list, tuple, set)): - if not urlpath: - raise ValueError("empty urlpath sequence") - urlpath0 = stringify_path(next(iter(urlpath))) - else: - urlpath0 = stringify_path(urlpath) - storage_options = storage_options or {} - if protocol: - storage_options["protocol"] = protocol - chain = _un_chain(urlpath0, storage_options or {}) - inkwargs = {} - # Reverse iterate the chain, creating a nested target_* structure - for i, ch in enumerate(reversed(chain)): - urls, nested_protocol, kw = ch - if i == len(chain) - 1: - inkwargs = dict(**kw, **inkwargs) - continue - inkwargs["target_options"] = dict(**kw, **inkwargs) - inkwargs["target_protocol"] = nested_protocol - inkwargs["fo"] = urls - paths, protocol, _ = chain[0] - fs = filesystem(protocol, **inkwargs) - if isinstance(urlpath, (list, tuple, set)): - pchains = [ - _un_chain(stringify_path(u), storage_options or {})[0] for u in urlpath - ] - if len({pc[1] for pc in pchains}) > 1: - raise ValueError("Protocol mismatch getting fs from %s", urlpath) - paths = [pc[0] for pc in pchains] - else: - paths = fs._strip_protocol(paths) - if isinstance(paths, (list, tuple, set)): - if expand: - paths = expand_paths_if_needed(paths, mode, num, fs, name_function) - elif not isinstance(paths, list): - paths = list(paths) - else: - if ("w" in mode or "x" in mode) and expand: - paths = _expand_paths(paths, name_function, num) - elif "*" in paths: - paths = [f for f in sorted(fs.glob(paths)) if not fs.isdir(f)] - else: - paths = [paths] - - return fs, fs._fs_token, paths - - -def _expand_paths(path, name_function, num): - if isinstance(path, str): - if path.count("*") > 1: - raise ValueError("Output path spec must contain exactly one '*'.") - elif "*" not in path: - path = os.path.join(path, "*.part") - - if name_function is None: - name_function = build_name_function(num - 1) - - paths = [path.replace("*", name_function(i)) for i in range(num)] - if paths != sorted(paths): - logger.warning( - "In order to preserve order between partitions" - " paths created with ``name_function`` should " - "sort to partition order" - ) - elif isinstance(path, (tuple, list)): - assert len(path) == num - paths = list(path) - else: - raise ValueError( - "Path should be either\n" - "1. A list of paths: ['foo.json', 'bar.json', ...]\n" - "2. A directory: 'foo/\n" - "3. A path with a '*' in it: 'foo.*.json'" - ) - return paths - - -class PickleableTextIOWrapper(io.TextIOWrapper): - """TextIOWrapper cannot be pickled. This solves it. - - Requires that ``buffer`` be pickleable, which all instances of - AbstractBufferedFile are. - """ - - def __init__( - self, - buffer, - encoding=None, - errors=None, - newline=None, - line_buffering=False, - write_through=False, - ): - self.args = buffer, encoding, errors, newline, line_buffering, write_through - super().__init__(*self.args) - - def __reduce__(self): - return PickleableTextIOWrapper, self.args diff --git a/venv/lib/python3.10/site-packages/fsspec/dircache.py b/venv/lib/python3.10/site-packages/fsspec/dircache.py deleted file mode 100644 index eca19566b135e5a7a4f6e7407d56411ec58bfe44..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/dircache.py +++ /dev/null @@ -1,98 +0,0 @@ -import time -from collections.abc import MutableMapping -from functools import lru_cache - - -class DirCache(MutableMapping): - """ - Caching of directory listings, in a structure like:: - - {"path0": [ - {"name": "path0/file0", - "size": 123, - "type": "file", - ... - }, - {"name": "path0/file1", - }, - ... - ], - "path1": [...] - } - - Parameters to this class control listing expiry or indeed turn - caching off - """ - - def __init__( - self, - use_listings_cache=True, - listings_expiry_time=None, - max_paths=None, - **kwargs, - ): - """ - - Parameters - ---------- - use_listings_cache: bool - If False, this cache never returns items, but always reports KeyError, - and setting items has no effect - listings_expiry_time: int or float (optional) - Time in seconds that a listing is considered valid. If None, - listings do not expire. - max_paths: int (optional) - The number of most recent listings that are considered valid; 'recent' - refers to when the entry was set. - """ - self._cache = {} - self._times = {} - if max_paths: - self._q = lru_cache(max_paths + 1)(lambda key: self._cache.pop(key, None)) - self.use_listings_cache = use_listings_cache - self.listings_expiry_time = listings_expiry_time - self.max_paths = max_paths - - def __getitem__(self, item): - if self.listings_expiry_time is not None: - if self._times.get(item, 0) - time.time() < -self.listings_expiry_time: - del self._cache[item] - if self.max_paths: - self._q(item) - return self._cache[item] # maybe raises KeyError - - def clear(self): - self._cache.clear() - - def __len__(self): - return len(self._cache) - - def __contains__(self, item): - try: - self[item] - return True - except KeyError: - return False - - def __setitem__(self, key, value): - if not self.use_listings_cache: - return - if self.max_paths: - self._q(key) - self._cache[key] = value - if self.listings_expiry_time is not None: - self._times[key] = time.time() - - def __delitem__(self, key): - del self._cache[key] - - def __iter__(self): - entries = list(self._cache) - - return (k for k in entries if k in self) - - def __reduce__(self): - return ( - DirCache, - (self.use_listings_cache, self.listings_expiry_time, self.max_paths), - ) diff --git a/venv/lib/python3.10/site-packages/fsspec/exceptions.py b/venv/lib/python3.10/site-packages/fsspec/exceptions.py deleted file mode 100644 index ae8905475f02655f4fc5863931d99ca9da55db78..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/exceptions.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -fsspec user-defined exception classes -""" - -import asyncio - - -class BlocksizeMismatchError(ValueError): - """ - Raised when a cached file is opened with a different blocksize than it was - written with - """ - - -class FSTimeoutError(asyncio.TimeoutError): - """ - Raised when a fsspec function timed out occurs - """ diff --git a/venv/lib/python3.10/site-packages/fsspec/fuse.py b/venv/lib/python3.10/site-packages/fsspec/fuse.py deleted file mode 100644 index 566d520fce3e94e3bbaee48c3c6acc9f1db315a8..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/fuse.py +++ /dev/null @@ -1,324 +0,0 @@ -import argparse -import logging -import os -import stat -import threading -import time -from errno import EIO, ENOENT - -from fuse import FUSE, FuseOSError, LoggingMixIn, Operations - -from fsspec import __version__ -from fsspec.core import url_to_fs - -logger = logging.getLogger("fsspec.fuse") - - -class FUSEr(Operations): - def __init__(self, fs, path, ready_file=False): - self.fs = fs - self.cache = {} - self.root = path.rstrip("/") + "/" - self.counter = 0 - logger.info("Starting FUSE at %s", path) - self._ready_file = ready_file - - def getattr(self, path, fh=None): - logger.debug("getattr %s", path) - if self._ready_file and path in ["/.fuse_ready", ".fuse_ready"]: - return {"type": "file", "st_size": 5} - - path = "".join([self.root, path.lstrip("/")]).rstrip("/") - try: - info = self.fs.info(path) - except FileNotFoundError as exc: - raise FuseOSError(ENOENT) from exc - - data = {"st_uid": info.get("uid", 1000), "st_gid": info.get("gid", 1000)} - perm = info.get("mode", 0o777) - - if info["type"] != "file": - data["st_mode"] = stat.S_IFDIR | perm - data["st_size"] = 0 - data["st_blksize"] = 0 - else: - data["st_mode"] = stat.S_IFREG | perm - data["st_size"] = info["size"] - data["st_blksize"] = 5 * 2**20 - data["st_nlink"] = 1 - data["st_atime"] = info["atime"] if "atime" in info else time.time() - data["st_ctime"] = info["ctime"] if "ctime" in info else time.time() - data["st_mtime"] = info["mtime"] if "mtime" in info else time.time() - return data - - def readdir(self, path, fh): - logger.debug("readdir %s", path) - path = "".join([self.root, path.lstrip("/")]) - files = self.fs.ls(path, False) - files = [os.path.basename(f.rstrip("/")) for f in files] - return [".", ".."] + files - - def mkdir(self, path, mode): - path = "".join([self.root, path.lstrip("/")]) - self.fs.mkdir(path) - return 0 - - def rmdir(self, path): - path = "".join([self.root, path.lstrip("/")]) - self.fs.rmdir(path) - return 0 - - def read(self, path, size, offset, fh): - logger.debug("read %s", (path, size, offset)) - if self._ready_file and path in ["/.fuse_ready", ".fuse_ready"]: - # status indicator - return b"ready" - - f = self.cache[fh] - f.seek(offset) - out = f.read(size) - return out - - def write(self, path, data, offset, fh): - logger.debug("write %s", (path, offset)) - f = self.cache[fh] - f.seek(offset) - f.write(data) - return len(data) - - def create(self, path, flags, fi=None): - logger.debug("create %s", (path, flags)) - fn = "".join([self.root, path.lstrip("/")]) - self.fs.touch(fn) # OS will want to get attributes immediately - f = self.fs.open(fn, "wb") - self.cache[self.counter] = f - self.counter += 1 - return self.counter - 1 - - def open(self, path, flags): - logger.debug("open %s", (path, flags)) - fn = "".join([self.root, path.lstrip("/")]) - if flags % 2 == 0: - # read - mode = "rb" - else: - # write/create - mode = "wb" - self.cache[self.counter] = self.fs.open(fn, mode) - self.counter += 1 - return self.counter - 1 - - def truncate(self, path, length, fh=None): - fn = "".join([self.root, path.lstrip("/")]) - if length != 0: - raise NotImplementedError - # maybe should be no-op since open with write sets size to zero anyway - self.fs.touch(fn) - - def unlink(self, path): - fn = "".join([self.root, path.lstrip("/")]) - try: - self.fs.rm(fn, False) - except (OSError, FileNotFoundError) as exc: - raise FuseOSError(EIO) from exc - - def release(self, path, fh): - try: - if fh in self.cache: - f = self.cache[fh] - f.close() - self.cache.pop(fh) - except Exception as e: - print(e) - return 0 - - def chmod(self, path, mode): - if hasattr(self.fs, "chmod"): - path = "".join([self.root, path.lstrip("/")]) - return self.fs.chmod(path, mode) - raise NotImplementedError - - -def run( - fs, - path, - mount_point, - foreground=True, - threads=False, - ready_file=False, - ops_class=FUSEr, -): - """Mount stuff in a local directory - - This uses fusepy to make it appear as if a given path on an fsspec - instance is in fact resident within the local file-system. - - This requires that fusepy by installed, and that FUSE be available on - the system (typically requiring a package to be installed with - apt, yum, brew, etc.). - - Parameters - ---------- - fs: file-system instance - From one of the compatible implementations - path: str - Location on that file-system to regard as the root directory to - mount. Note that you typically should include the terminating "/" - character. - mount_point: str - An empty directory on the local file-system where the contents of - the remote path will appear. - foreground: bool - Whether or not calling this function will block. Operation will - typically be more stable if True. - threads: bool - Whether or not to create threads when responding to file operations - within the mounter directory. Operation will typically be more - stable if False. - ready_file: bool - Whether the FUSE process is ready. The ``.fuse_ready`` file will - exist in the ``mount_point`` directory if True. Debugging purpose. - ops_class: FUSEr or Subclass of FUSEr - To override the default behavior of FUSEr. For Example, logging - to file. - - """ - func = lambda: FUSE( - ops_class(fs, path, ready_file=ready_file), - mount_point, - nothreads=not threads, - foreground=foreground, - ) - if not foreground: - th = threading.Thread(target=func) - th.daemon = True - th.start() - return th - else: # pragma: no cover - try: - func() - except KeyboardInterrupt: - pass - - -def main(args): - """Mount filesystem from chained URL to MOUNT_POINT. - - Examples: - - python3 -m fsspec.fuse memory /usr/share /tmp/mem - - python3 -m fsspec.fuse local /tmp/source /tmp/local \\ - -l /tmp/fsspecfuse.log - - You can also mount chained-URLs and use special settings: - - python3 -m fsspec.fuse 'filecache::zip::file://data.zip' \\ - / /tmp/zip \\ - -o 'filecache-cache_storage=/tmp/simplecache' - - You can specify the type of the setting by using `[int]` or `[bool]`, - (`true`, `yes`, `1` represents the Boolean value `True`): - - python3 -m fsspec.fuse 'simplecache::ftp://ftp1.at.proftpd.org' \\ - /historic/packages/RPMS /tmp/ftp \\ - -o 'simplecache-cache_storage=/tmp/simplecache' \\ - -o 'simplecache-check_files=false[bool]' \\ - -o 'ftp-listings_expiry_time=60[int]' \\ - -o 'ftp-username=anonymous' \\ - -o 'ftp-password=xieyanbo' - """ - - class RawDescriptionArgumentParser(argparse.ArgumentParser): - def format_help(self): - usage = super().format_help() - parts = usage.split("\n\n") - parts[1] = self.description.rstrip() - return "\n\n".join(parts) - - parser = RawDescriptionArgumentParser(prog="fsspec.fuse", description=main.__doc__) - parser.add_argument("--version", action="version", version=__version__) - parser.add_argument("url", type=str, help="fs url") - parser.add_argument("source_path", type=str, help="source directory in fs") - parser.add_argument("mount_point", type=str, help="local directory") - parser.add_argument( - "-o", - "--option", - action="append", - help="Any options of protocol included in the chained URL", - ) - parser.add_argument( - "-l", "--log-file", type=str, help="Logging FUSE debug info (Default: '')" - ) - parser.add_argument( - "-f", - "--foreground", - action="store_false", - help="Running in foreground or not (Default: False)", - ) - parser.add_argument( - "-t", - "--threads", - action="store_false", - help="Running with threads support (Default: False)", - ) - parser.add_argument( - "-r", - "--ready-file", - action="store_false", - help="The `.fuse_ready` file will exist after FUSE is ready. " - "(Debugging purpose, Default: False)", - ) - args = parser.parse_args(args) - - kwargs = {} - for item in args.option or []: - key, sep, value = item.partition("=") - if not sep: - parser.error(message=f"Wrong option: {item!r}") - val = value.lower() - if val.endswith("[int]"): - value = int(value[: -len("[int]")]) - elif val.endswith("[bool]"): - value = val[: -len("[bool]")] in ["1", "yes", "true"] - - if "-" in key: - fs_name, setting_name = key.split("-", 1) - if fs_name in kwargs: - kwargs[fs_name][setting_name] = value - else: - kwargs[fs_name] = {setting_name: value} - else: - kwargs[key] = value - - if args.log_file: - logging.basicConfig( - level=logging.DEBUG, - filename=args.log_file, - format="%(asctime)s %(message)s", - ) - - class LoggingFUSEr(FUSEr, LoggingMixIn): - pass - - fuser = LoggingFUSEr - else: - fuser = FUSEr - - fs, url_path = url_to_fs(args.url, **kwargs) - logger.debug("Mounting %s to %s", url_path, str(args.mount_point)) - run( - fs, - args.source_path, - args.mount_point, - foreground=args.foreground, - threads=args.threads, - ready_file=args.ready_file, - ops_class=fuser, - ) - - -if __name__ == "__main__": - import sys - - main(sys.argv[1:]) diff --git a/venv/lib/python3.10/site-packages/fsspec/generic.py b/venv/lib/python3.10/site-packages/fsspec/generic.py deleted file mode 100644 index 0a641b0e2bcf70729a44064319eecb3647450379..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/generic.py +++ /dev/null @@ -1,396 +0,0 @@ -from __future__ import annotations - -import inspect -import logging -import os -import shutil -import uuid - -from .asyn import AsyncFileSystem, _run_coros_in_chunks, sync_wrapper -from .callbacks import DEFAULT_CALLBACK -from .core import filesystem, get_filesystem_class, split_protocol, url_to_fs - -_generic_fs = {} -logger = logging.getLogger("fsspec.generic") - - -def set_generic_fs(protocol, **storage_options): - """Populate the dict used for method=="generic" lookups""" - _generic_fs[protocol] = filesystem(protocol, **storage_options) - - -def _resolve_fs(url, method, protocol=None, storage_options=None): - """Pick instance of backend FS""" - url = url[0] if isinstance(url, (list, tuple)) else url - protocol = protocol or split_protocol(url)[0] - storage_options = storage_options or {} - if method == "default": - return filesystem(protocol) - if method == "generic": - return _generic_fs[protocol] - if method == "current": - cls = get_filesystem_class(protocol) - return cls.current() - if method == "options": - fs, _ = url_to_fs(url, **storage_options.get(protocol, {})) - return fs - raise ValueError(f"Unknown FS resolution method: {method}") - - -def rsync( - source, - destination, - delete_missing=False, - source_field="size", - dest_field="size", - update_cond="different", - inst_kwargs=None, - fs=None, - **kwargs, -): - """Sync files between two directory trees - - (experimental) - - Parameters - ---------- - source: str - Root of the directory tree to take files from. This must be a directory, but - do not include any terminating "/" character - destination: str - Root path to copy into. The contents of this location should be - identical to the contents of ``source`` when done. This will be made a - directory, and the terminal "/" should not be included. - delete_missing: bool - If there are paths in the destination that don't exist in the - source and this is True, delete them. Otherwise, leave them alone. - source_field: str | callable - If ``update_field`` is "different", this is the key in the info - of source files to consider for difference. Maybe a function of the - info dict. - dest_field: str | callable - If ``update_field`` is "different", this is the key in the info - of destination files to consider for difference. May be a function of - the info dict. - update_cond: "different"|"always"|"never" - If "always", every file is copied, regardless of whether it exists in - the destination. If "never", files that exist in the destination are - not copied again. If "different" (default), only copy if the info - fields given by ``source_field`` and ``dest_field`` (usually "size") - are different. Other comparisons may be added in the future. - inst_kwargs: dict|None - If ``fs`` is None, use this set of keyword arguments to make a - GenericFileSystem instance - fs: GenericFileSystem|None - Instance to use if explicitly given. The instance defines how to - to make downstream file system instances from paths. - - Returns - ------- - dict of the copy operations that were performed, {source: destination} - """ - fs = fs or GenericFileSystem(**(inst_kwargs or {})) - source = fs._strip_protocol(source) - destination = fs._strip_protocol(destination) - allfiles = fs.find(source, withdirs=True, detail=True) - if not fs.isdir(source): - raise ValueError("Can only rsync on a directory") - otherfiles = fs.find(destination, withdirs=True, detail=True) - dirs = [ - a - for a, v in allfiles.items() - if v["type"] == "directory" and a.replace(source, destination) not in otherfiles - ] - logger.debug(f"{len(dirs)} directories to create") - if dirs: - fs.make_many_dirs( - [dirn.replace(source, destination) for dirn in dirs], exist_ok=True - ) - allfiles = {a: v for a, v in allfiles.items() if v["type"] == "file"} - logger.debug(f"{len(allfiles)} files to consider for copy") - to_delete = [ - o - for o, v in otherfiles.items() - if o.replace(destination, source) not in allfiles and v["type"] == "file" - ] - for k, v in allfiles.copy().items(): - otherfile = k.replace(source, destination) - if otherfile in otherfiles: - if update_cond == "always": - allfiles[k] = otherfile - elif update_cond == "never": - allfiles.pop(k) - elif update_cond == "different": - inf1 = source_field(v) if callable(source_field) else v[source_field] - v2 = otherfiles[otherfile] - inf2 = dest_field(v2) if callable(dest_field) else v2[dest_field] - if inf1 != inf2: - # details mismatch, make copy - allfiles[k] = otherfile - else: - # details match, don't copy - allfiles.pop(k) - else: - # file not in target yet - allfiles[k] = otherfile - logger.debug(f"{len(allfiles)} files to copy") - if allfiles: - source_files, target_files = zip(*allfiles.items()) - fs.cp(source_files, target_files, **kwargs) - logger.debug(f"{len(to_delete)} files to delete") - if delete_missing and to_delete: - fs.rm(to_delete) - return allfiles - - -class GenericFileSystem(AsyncFileSystem): - """Wrapper over all other FS types - - - - This implementation is a single unified interface to be able to run FS operations - over generic URLs, and dispatch to the specific implementations using the URL - protocol prefix. - - Note: instances of this FS are always async, even if you never use it with any async - backend. - """ - - protocol = "generic" # there is no real reason to ever use a protocol with this FS - - def __init__(self, default_method="default", storage_options=None, **kwargs): - """ - - Parameters - ---------- - default_method: str (optional) - Defines how to configure backend FS instances. Options are: - - "default": instantiate like FSClass(), with no - extra arguments; this is the default instance of that FS, and can be - configured via the config system - - "generic": takes instances from the `_generic_fs` dict in this module, - which you must populate before use. Keys are by protocol - - "options": expects storage_options, a dict mapping protocol to - kwargs to use when constructing the filesystem - - "current": takes the most recently instantiated version of each FS - """ - self.method = default_method - self.st_opts = storage_options - super().__init__(**kwargs) - - def _parent(self, path): - fs = _resolve_fs(path, self.method, storage_options=self.st_opts) - return fs.unstrip_protocol(fs._parent(path)) - - def _strip_protocol(self, path): - # normalization only - fs = _resolve_fs(path, self.method, storage_options=self.st_opts) - return fs.unstrip_protocol(fs._strip_protocol(path)) - - async def _find(self, path, maxdepth=None, withdirs=False, detail=False, **kwargs): - fs = _resolve_fs(path, self.method, storage_options=self.st_opts) - if fs.async_impl: - out = await fs._find( - path, maxdepth=maxdepth, withdirs=withdirs, detail=True, **kwargs - ) - else: - out = fs.find( - path, maxdepth=maxdepth, withdirs=withdirs, detail=True, **kwargs - ) - result = {} - for k, v in out.items(): - v = v.copy() # don't corrupt target FS dircache - name = fs.unstrip_protocol(k) - v["name"] = name - result[name] = v - if detail: - return result - return list(result) - - async def _info(self, url, **kwargs): - fs = _resolve_fs(url, self.method) - if fs.async_impl: - out = await fs._info(url, **kwargs) - else: - out = fs.info(url, **kwargs) - out = out.copy() # don't edit originals - out["name"] = fs.unstrip_protocol(out["name"]) - return out - - async def _ls( - self, - url, - detail=True, - **kwargs, - ): - fs = _resolve_fs(url, self.method) - if fs.async_impl: - out = await fs._ls(url, detail=True, **kwargs) - else: - out = fs.ls(url, detail=True, **kwargs) - out = [o.copy() for o in out] # don't edit originals - for o in out: - o["name"] = fs.unstrip_protocol(o["name"]) - if detail: - return out - else: - return [o["name"] for o in out] - - async def _cat_file( - self, - url, - **kwargs, - ): - fs = _resolve_fs(url, self.method) - if fs.async_impl: - return await fs._cat_file(url, **kwargs) - else: - return fs.cat_file(url, **kwargs) - - async def _pipe_file( - self, - path, - value, - **kwargs, - ): - fs = _resolve_fs(path, self.method, storage_options=self.st_opts) - if fs.async_impl: - return await fs._pipe_file(path, value, **kwargs) - else: - return fs.pipe_file(path, value, **kwargs) - - async def _rm(self, url, **kwargs): - urls = url - if isinstance(urls, str): - urls = [urls] - fs = _resolve_fs(urls[0], self.method) - if fs.async_impl: - await fs._rm(urls, **kwargs) - else: - fs.rm(url, **kwargs) - - async def _makedirs(self, path, exist_ok=False): - logger.debug("Make dir %s", path) - fs = _resolve_fs(path, self.method, storage_options=self.st_opts) - if fs.async_impl: - await fs._makedirs(path, exist_ok=exist_ok) - else: - fs.makedirs(path, exist_ok=exist_ok) - - def rsync(self, source, destination, **kwargs): - """Sync files between two directory trees - - See `func:rsync` for more details. - """ - rsync(source, destination, fs=self, **kwargs) - - async def _cp_file( - self, - url, - url2, - blocksize=2**20, - callback=DEFAULT_CALLBACK, - tempdir: str | None = None, - **kwargs, - ): - fs = _resolve_fs(url, self.method) - fs2 = _resolve_fs(url2, self.method) - if fs is fs2: - # pure remote - if fs.async_impl: - return await fs._copy(url, url2, **kwargs) - else: - return fs.copy(url, url2, **kwargs) - await copy_file_op(fs, [url], fs2, [url2], tempdir, 1, on_error="raise") - - async def _make_many_dirs(self, urls, exist_ok=True): - fs = _resolve_fs(urls[0], self.method) - if fs.async_impl: - coros = [fs._makedirs(u, exist_ok=exist_ok) for u in urls] - await _run_coros_in_chunks(coros) - else: - for u in urls: - fs.makedirs(u, exist_ok=exist_ok) - - make_many_dirs = sync_wrapper(_make_many_dirs) - - async def _copy( - self, - path1: list[str], - path2: list[str], - recursive: bool = False, - on_error: str = "ignore", - maxdepth: int | None = None, - batch_size: int | None = None, - tempdir: str | None = None, - **kwargs, - ): - # TODO: special case for one FS being local, which can use get/put - # TODO: special case for one being memFS, which can use cat/pipe - if recursive: - raise NotImplementedError("Please use fsspec.generic.rsync") - path1 = [path1] if isinstance(path1, str) else path1 - path2 = [path2] if isinstance(path2, str) else path2 - - fs = _resolve_fs(path1, self.method) - fs2 = _resolve_fs(path2, self.method) - - if fs is fs2: - if fs.async_impl: - return await fs._copy(path1, path2, **kwargs) - else: - return fs.copy(path1, path2, **kwargs) - - await copy_file_op( - fs, path1, fs2, path2, tempdir, batch_size, on_error=on_error - ) - - -async def copy_file_op( - fs1, url1, fs2, url2, tempdir=None, batch_size=20, on_error="ignore" -): - import tempfile - - tempdir = tempdir or tempfile.mkdtemp() - try: - coros = [ - _copy_file_op( - fs1, - u1, - fs2, - u2, - os.path.join(tempdir, uuid.uuid4().hex), - ) - for u1, u2 in zip(url1, url2) - ] - out = await _run_coros_in_chunks( - coros, batch_size=batch_size, return_exceptions=True - ) - finally: - shutil.rmtree(tempdir) - if on_error == "return": - return out - elif on_error == "raise": - for o in out: - if isinstance(o, Exception): - raise o - - -async def _copy_file_op(fs1, url1, fs2, url2, local, on_error="ignore"): - if fs1.async_impl: - await fs1._get_file(url1, local) - else: - fs1.get_file(url1, local) - if fs2.async_impl: - await fs2._put_file(local, url2) - else: - fs2.put_file(local, url2) - os.unlink(local) - logger.debug("Copy %s -> %s; done", url1, url2) - - -async def maybe_await(cor): - if inspect.iscoroutine(cor): - return await cor - else: - return cor diff --git a/venv/lib/python3.10/site-packages/fsspec/gui.py b/venv/lib/python3.10/site-packages/fsspec/gui.py deleted file mode 100644 index 9d914c8beb6cabb2c2700eb8eee31028559be2bd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/gui.py +++ /dev/null @@ -1,417 +0,0 @@ -import ast -import contextlib -import logging -import os -import re -from collections.abc import Sequence -from typing import ClassVar - -import panel as pn - -from .core import OpenFile, get_filesystem_class, split_protocol -from .registry import known_implementations - -pn.extension() -logger = logging.getLogger("fsspec.gui") - - -class SigSlot: - """Signal-slot mixin, for Panel event passing - - Include this class in a widget manager's superclasses to be able to - register events and callbacks on Panel widgets managed by that class. - - The method ``_register`` should be called as widgets are added, and external - code should call ``connect`` to associate callbacks. - - By default, all signals emit a DEBUG logging statement. - """ - - # names of signals that this class may emit each of which must be - # set by _register for any new instance - signals: ClassVar[Sequence[str]] = [] - # names of actions that this class may respond to - slots: ClassVar[Sequence[str]] = [] - - # each of which must be a method name - - def __init__(self): - self._ignoring_events = False - self._sigs = {} - self._map = {} - self._setup() - - def _setup(self): - """Create GUI elements and register signals""" - self.panel = pn.pane.PaneBase() - # no signals to set up in the base class - - def _register( - self, widget, name, thing="value", log_level=logging.DEBUG, auto=False - ): - """Watch the given attribute of a widget and assign it a named event - - This is normally called at the time a widget is instantiated, in the - class which owns it. - - Parameters - ---------- - widget : pn.layout.Panel or None - Widget to watch. If None, an anonymous signal not associated with - any widget. - name : str - Name of this event - thing : str - Attribute of the given widget to watch - log_level : int - When the signal is triggered, a logging event of the given level - will be fired in the dfviz logger. - auto : bool - If True, automatically connects with a method in this class of the - same name. - """ - if name not in self.signals: - raise ValueError(f"Attempt to assign an undeclared signal: {name}") - self._sigs[name] = { - "widget": widget, - "callbacks": [], - "thing": thing, - "log": log_level, - } - wn = "-".join( - [ - getattr(widget, "name", str(widget)) if widget is not None else "none", - thing, - ] - ) - self._map[wn] = name - if widget is not None: - widget.param.watch(self._signal, thing, onlychanged=True) - if auto and hasattr(self, name): - self.connect(name, getattr(self, name)) - - def _repr_mimebundle_(self, *args, **kwargs): - """Display in a notebook or a server""" - try: - return self.panel._repr_mimebundle_(*args, **kwargs) - except (ValueError, AttributeError) as exc: - raise NotImplementedError( - "Panel does not seem to be set up properly" - ) from exc - - def connect(self, signal, slot): - """Associate call back with given event - - The callback must be a function which takes the "new" value of the - watched attribute as the only parameter. If the callback return False, - this cancels any further processing of the given event. - - Alternatively, the callback can be a string, in which case it means - emitting the correspondingly-named event (i.e., connect to self) - """ - self._sigs[signal]["callbacks"].append(slot) - - def _signal(self, event): - """This is called by a an action on a widget - - Within an self.ignore_events context, nothing happens. - - Tests can execute this method by directly changing the values of - widget components. - """ - if not self._ignoring_events: - wn = "-".join([event.obj.name, event.name]) - if wn in self._map and self._map[wn] in self._sigs: - self._emit(self._map[wn], event.new) - - @contextlib.contextmanager - def ignore_events(self): - """Temporarily turn off events processing in this instance - - (does not propagate to children) - """ - self._ignoring_events = True - try: - yield - finally: - self._ignoring_events = False - - def _emit(self, sig, value=None): - """An event happened, call its callbacks - - This method can be used in tests to simulate message passing without - directly changing visual elements. - - Calling of callbacks will halt whenever one returns False. - """ - logger.log(self._sigs[sig]["log"], f"{sig}: {value}") - for callback in self._sigs[sig]["callbacks"]: - if isinstance(callback, str): - self._emit(callback) - else: - try: - # running callbacks should not break the interface - ret = callback(value) - if ret is False: - break - except Exception as e: - logger.exception( - "Exception (%s) while executing callback for signal: %s", - e, - sig, - ) - - def show(self, threads=False): - """Open a new browser tab and display this instance's interface""" - self.panel.show(threads=threads, verbose=False) - return self - - -class SingleSelect(SigSlot): - """A multiselect which only allows you to select one item for an event""" - - signals = ["_selected", "selected"] # the first is internal - slots = ["set_options", "set_selection", "add", "clear", "select"] - - def __init__(self, **kwargs): - self.kwargs = kwargs - super().__init__() - - def _setup(self): - self.panel = pn.widgets.MultiSelect(**self.kwargs) - self._register(self.panel, "_selected", "value") - self._register(None, "selected") - self.connect("_selected", self.select_one) - - def _signal(self, *args, **kwargs): - super()._signal(*args, **kwargs) - - def select_one(self, *_): - with self.ignore_events(): - val = [self.panel.value[-1]] if self.panel.value else [] - self.panel.value = val - self._emit("selected", self.panel.value) - - def set_options(self, options): - self.panel.options = options - - def clear(self): - self.panel.options = [] - - @property - def value(self): - return self.panel.value - - def set_selection(self, selection): - self.panel.value = [selection] - - -class FileSelector(SigSlot): - """Panel-based graphical file selector widget - - Instances of this widget are interactive and can be displayed in jupyter by having - them as the output of a cell, or in a separate browser tab using ``.show()``. - """ - - signals = [ - "protocol_changed", - "selection_changed", - "directory_entered", - "home_clicked", - "up_clicked", - "go_clicked", - "filters_changed", - ] - slots = ["set_filters", "go_home"] - - def __init__(self, url=None, filters=None, ignore=None, kwargs=None): - """ - - Parameters - ---------- - url : str (optional) - Initial value of the URL to populate the dialog; should include protocol - filters : list(str) (optional) - File endings to include in the listings. If not included, all files are - allowed. Does not affect directories. - If given, the endings will appear as checkboxes in the interface - ignore : list(str) (optional) - Regex(s) of file basename patterns to ignore, e.g., "\\." for typical - hidden files on posix - kwargs : dict (optional) - To pass to file system instance - """ - if url: - self.init_protocol, url = split_protocol(url) - else: - self.init_protocol, url = "file", os.getcwd() - self.init_url = url - self.init_kwargs = (kwargs if isinstance(kwargs, str) else str(kwargs)) or "{}" - self.filters = filters - self.ignore = [re.compile(i) for i in ignore or []] - self._fs = None - super().__init__() - - def _setup(self): - self.url = pn.widgets.TextInput( - name="url", - value=self.init_url, - align="end", - sizing_mode="stretch_width", - width_policy="max", - ) - self.protocol = pn.widgets.Select( - options=sorted(known_implementations), - value=self.init_protocol, - name="protocol", - align="center", - ) - self.kwargs = pn.widgets.TextInput( - name="kwargs", value=self.init_kwargs, align="center" - ) - self.go = pn.widgets.Button(name="⇨", align="end", width=45) - self.main = SingleSelect(size=10) - self.home = pn.widgets.Button(name="🏠", width=40, height=30, align="end") - self.up = pn.widgets.Button(name="‹", width=30, height=30, align="end") - - self._register(self.protocol, "protocol_changed", auto=True) - self._register(self.go, "go_clicked", "clicks", auto=True) - self._register(self.up, "up_clicked", "clicks", auto=True) - self._register(self.home, "home_clicked", "clicks", auto=True) - self._register(None, "selection_changed") - self.main.connect("selected", self.selection_changed) - self._register(None, "directory_entered") - self.prev_protocol = self.protocol.value - self.prev_kwargs = self.storage_options - - self.filter_sel = pn.widgets.CheckBoxGroup( - value=[], options=[], inline=False, align="end", width_policy="min" - ) - self._register(self.filter_sel, "filters_changed", auto=True) - - self.panel = pn.Column( - pn.Row(self.protocol, self.kwargs), - pn.Row(self.home, self.up, self.url, self.go, self.filter_sel), - self.main.panel, - ) - self.set_filters(self.filters) - self.go_clicked() - - def set_filters(self, filters=None): - self.filters = filters - if filters: - self.filter_sel.options = filters - self.filter_sel.value = filters - else: - self.filter_sel.options = [] - self.filter_sel.value = [] - - @property - def storage_options(self): - """Value of the kwargs box as a dictionary""" - return ast.literal_eval(self.kwargs.value) or {} - - @property - def fs(self): - """Current filesystem instance""" - if self._fs is None: - cls = get_filesystem_class(self.protocol.value) - self._fs = cls(**self.storage_options) - return self._fs - - @property - def urlpath(self): - """URL of currently selected item""" - return ( - (f"{self.protocol.value}://{self.main.value[0]}") - if self.main.value - else None - ) - - def open_file(self, mode="rb", compression=None, encoding=None): - """Create OpenFile instance for the currently selected item - - For example, in a notebook you might do something like - - .. code-block:: - - [ ]: sel = FileSelector(); sel - - # user selects their file - - [ ]: with sel.open_file('rb') as f: - ... out = f.read() - - Parameters - ---------- - mode: str (optional) - Open mode for the file. - compression: str (optional) - The interact with the file as compressed. Set to 'infer' to guess - compression from the file ending - encoding: str (optional) - If using text mode, use this encoding; defaults to UTF8. - """ - if self.urlpath is None: - raise ValueError("No file selected") - return OpenFile(self.fs, self.urlpath, mode, compression, encoding) - - def filters_changed(self, values): - self.filters = values - self.go_clicked() - - def selection_changed(self, *_): - if self.urlpath is None: - return - if self.fs.isdir(self.urlpath): - self.url.value = self.fs._strip_protocol(self.urlpath) - self.go_clicked() - - def go_clicked(self, *_): - if ( - self.prev_protocol != self.protocol.value - or self.prev_kwargs != self.storage_options - ): - self._fs = None # causes fs to be recreated - self.prev_protocol = self.protocol.value - self.prev_kwargs = self.storage_options - listing = sorted( - self.fs.ls(self.url.value, detail=True), key=lambda x: x["name"] - ) - listing = [ - l - for l in listing - if not any(i.match(l["name"].rsplit("/", 1)[-1]) for i in self.ignore) - ] - folders = { - "📁 " + o["name"].rsplit("/", 1)[-1]: o["name"] - for o in listing - if o["type"] == "directory" - } - files = { - "📄 " + o["name"].rsplit("/", 1)[-1]: o["name"] - for o in listing - if o["type"] == "file" - } - if self.filters: - files = { - k: v - for k, v in files.items() - if any(v.endswith(ext) for ext in self.filters) - } - self.main.set_options(dict(**folders, **files)) - - def protocol_changed(self, *_): - self._fs = None - self.main.options = [] - self.url.value = "" - - def home_clicked(self, *_): - self.protocol.value = self.init_protocol - self.kwargs.value = self.init_kwargs - self.url.value = self.init_url - self.go_clicked() - - def up_clicked(self, *_): - self.url.value = self.fs._parent(self.url.value) - self.go_clicked() diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__init__.py b/venv/lib/python3.10/site-packages/fsspec/implementations/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index ff445c28f546805e534dcd39ab8ba7629e5f0ea8..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/arrow.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/arrow.cpython-310.pyc deleted file mode 100644 index 49f98927a8ca4f97ee4e8b7e3349213da2e7a0d2..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/arrow.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/asyn_wrapper.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/asyn_wrapper.cpython-310.pyc deleted file mode 100644 index 482fd9c606c5df51d6ed9df2b55c0b046bc2b7c4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/asyn_wrapper.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cache_mapper.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cache_mapper.cpython-310.pyc deleted file mode 100644 index 7153da8ca3439e607ce680b8cfc513b6a2cd2874..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cache_mapper.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cache_metadata.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cache_metadata.cpython-310.pyc deleted file mode 100644 index a542eca3a34b607998df52566678d836176cacf7..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cache_metadata.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cached.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cached.cpython-310.pyc deleted file mode 100644 index 32e4ad636910d3c38d16d77941a1960ff360f23d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/cached.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/chained.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/chained.cpython-310.pyc deleted file mode 100644 index e203e208ffcc2e52ee34a511d157d8feb19d506f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/chained.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dask.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dask.cpython-310.pyc deleted file mode 100644 index 4eb37f44f4dd9f7d4a1988d831064787285a9550..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dask.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/data.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/data.cpython-310.pyc deleted file mode 100644 index 5541583c9948eb73b11f8c42a243335d8abf074a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/data.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dbfs.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dbfs.cpython-310.pyc deleted file mode 100644 index 3389ad17398268943c1abcdc6ff90038a932483a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dbfs.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dirfs.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dirfs.cpython-310.pyc deleted file mode 100644 index 76fdec988dc6e79c65ec372fb1d53eb6be11a1aa..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/dirfs.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/ftp.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/ftp.cpython-310.pyc deleted file mode 100644 index 5226164d879089d516b73d5816db244fa5e48a6f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/ftp.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/gist.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/gist.cpython-310.pyc deleted file mode 100644 index 9c0c76946aba6536ae0ec1bb1bf007f109ca9bdb..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/gist.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/git.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/git.cpython-310.pyc deleted file mode 100644 index 244693763888da74c6f8e09959a0a8687aaecaa0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/git.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/github.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/github.cpython-310.pyc deleted file mode 100644 index fd2573da570dd4cff2a8d3b8250dd770477eb603..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/github.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/http.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/http.cpython-310.pyc deleted file mode 100644 index 5d8c051cd8bd60ac0f6bac32d3abe5e3fde6c7ce..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/http.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/http_sync.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/http_sync.cpython-310.pyc deleted file mode 100644 index 9ea37ca96bddee904d14fde4610f3793ba889dc7..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/http_sync.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/jupyter.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/jupyter.cpython-310.pyc deleted file mode 100644 index 68d87dd284103e5a2b388d9b85222a7ae68b82f4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/jupyter.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/libarchive.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/libarchive.cpython-310.pyc deleted file mode 100644 index 10813e3e550ffadb56dbacf8f3782c4da6545a73..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/libarchive.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/local.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/local.cpython-310.pyc deleted file mode 100644 index 53f67d33d32c24d280bd80a3ec70a69596511571..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/local.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/memory.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/memory.cpython-310.pyc deleted file mode 100644 index 1437b611ef4e132ee5c6994d7b2192d4a61a14c6..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/memory.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/reference.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/reference.cpython-310.pyc deleted file mode 100644 index 4c9232768d268526ee6005562705cae46ea48fe3..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/reference.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/sftp.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/sftp.cpython-310.pyc deleted file mode 100644 index be53b9fab5540a4dee8a119a9ac4ddaa096427a0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/sftp.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/smb.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/smb.cpython-310.pyc deleted file mode 100644 index b218321c0e8de9c9104a874d2619653c884972e4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/smb.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/tar.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/tar.cpython-310.pyc deleted file mode 100644 index 441fbc9344995754894297b2ed135ef813bd5130..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/tar.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/webhdfs.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/webhdfs.cpython-310.pyc deleted file mode 100644 index 5076b525869483b14ce781b31e7503e50b4d18ff..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/webhdfs.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/zip.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/zip.cpython-310.pyc deleted file mode 100644 index 22adfc34ded3c7a48c243057e726c273dc5999af..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/implementations/__pycache__/zip.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/arrow.py b/venv/lib/python3.10/site-packages/fsspec/implementations/arrow.py deleted file mode 100644 index 227d50930763f56bc8c01556249eb1306347350b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/arrow.py +++ /dev/null @@ -1,312 +0,0 @@ -import errno -import io -import os -import secrets -import shutil -from contextlib import suppress -from functools import cached_property, wraps -from urllib.parse import parse_qs - -from fsspec.spec import AbstractFileSystem -from fsspec.utils import ( - get_package_version_without_import, - infer_storage_options, - mirror_from, - tokenize, -) - - -def wrap_exceptions(func): - @wraps(func) - def wrapper(*args, **kwargs): - try: - return func(*args, **kwargs) - except OSError as exception: - if not exception.args: - raise - - message, *args = exception.args - if isinstance(message, str) and "does not exist" in message: - raise FileNotFoundError(errno.ENOENT, message) from exception - else: - raise - - return wrapper - - -PYARROW_VERSION = None - - -class ArrowFSWrapper(AbstractFileSystem): - """FSSpec-compatible wrapper of pyarrow.fs.FileSystem. - - Parameters - ---------- - fs : pyarrow.fs.FileSystem - - """ - - root_marker = "/" - - def __init__(self, fs, **kwargs): - global PYARROW_VERSION - PYARROW_VERSION = get_package_version_without_import("pyarrow") - self.fs = fs - super().__init__(**kwargs) - - @property - def protocol(self): - return self.fs.type_name - - @cached_property - def fsid(self): - return "hdfs_" + tokenize(self.fs.host, self.fs.port) - - @classmethod - def _strip_protocol(cls, path): - ops = infer_storage_options(path) - path = ops["path"] - if path.startswith("//"): - # special case for "hdfs://path" (without the triple slash) - path = path[1:] - return path - - def ls(self, path, detail=False, **kwargs): - path = self._strip_protocol(path) - from pyarrow.fs import FileSelector - - try: - entries = [ - self._make_entry(entry) - for entry in self.fs.get_file_info(FileSelector(path)) - ] - except (FileNotFoundError, NotADirectoryError): - entries = [self.info(path, **kwargs)] - if detail: - return entries - else: - return [entry["name"] for entry in entries] - - def info(self, path, **kwargs): - path = self._strip_protocol(path) - [info] = self.fs.get_file_info([path]) - return self._make_entry(info) - - def exists(self, path): - path = self._strip_protocol(path) - try: - self.info(path) - except FileNotFoundError: - return False - else: - return True - - def _make_entry(self, info): - from pyarrow.fs import FileType - - if info.type is FileType.Directory: - kind = "directory" - elif info.type is FileType.File: - kind = "file" - elif info.type is FileType.NotFound: - raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), info.path) - else: - kind = "other" - - return { - "name": info.path, - "size": info.size, - "type": kind, - "mtime": info.mtime, - } - - @wrap_exceptions - def cp_file(self, path1, path2, **kwargs): - path1 = self._strip_protocol(path1).rstrip("/") - path2 = self._strip_protocol(path2).rstrip("/") - - with self._open(path1, "rb") as lstream: - tmp_fname = f"{path2}.tmp.{secrets.token_hex(6)}" - try: - with self.open(tmp_fname, "wb") as rstream: - shutil.copyfileobj(lstream, rstream) - self.fs.move(tmp_fname, path2) - except BaseException: - with suppress(FileNotFoundError): - self.fs.delete_file(tmp_fname) - raise - - @wrap_exceptions - def mv(self, path1, path2, **kwargs): - path1 = self._strip_protocol(path1).rstrip("/") - path2 = self._strip_protocol(path2).rstrip("/") - self.fs.move(path1, path2) - - @wrap_exceptions - def rm_file(self, path): - path = self._strip_protocol(path) - self.fs.delete_file(path) - - @wrap_exceptions - def rm(self, path, recursive=False, maxdepth=None): - path = self._strip_protocol(path).rstrip("/") - if self.isdir(path): - if recursive: - self.fs.delete_dir(path) - else: - raise ValueError("Can't delete directories without recursive=False") - else: - self.fs.delete_file(path) - - @wrap_exceptions - def _open(self, path, mode="rb", block_size=None, seekable=True, **kwargs): - if mode == "rb": - if seekable: - method = self.fs.open_input_file - else: - method = self.fs.open_input_stream - elif mode == "wb": - method = self.fs.open_output_stream - elif mode == "ab": - method = self.fs.open_append_stream - else: - raise ValueError(f"unsupported mode for Arrow filesystem: {mode!r}") - - _kwargs = {} - if mode != "rb" or not seekable: - if int(PYARROW_VERSION.split(".")[0]) >= 4: - # disable compression auto-detection - _kwargs["compression"] = None - stream = method(path, **_kwargs) - - return ArrowFile(self, stream, path, mode, block_size, **kwargs) - - @wrap_exceptions - def mkdir(self, path, create_parents=True, **kwargs): - path = self._strip_protocol(path) - if create_parents: - self.makedirs(path, exist_ok=True) - else: - self.fs.create_dir(path, recursive=False) - - @wrap_exceptions - def makedirs(self, path, exist_ok=False): - path = self._strip_protocol(path) - self.fs.create_dir(path, recursive=True) - - @wrap_exceptions - def rmdir(self, path): - path = self._strip_protocol(path) - self.fs.delete_dir(path) - - @wrap_exceptions - def modified(self, path): - path = self._strip_protocol(path) - return self.fs.get_file_info(path).mtime - - def cat_file(self, path, start=None, end=None, **kwargs): - kwargs.setdefault("seekable", start not in [None, 0]) - return super().cat_file(path, start=None, end=None, **kwargs) - - def get_file(self, rpath, lpath, **kwargs): - kwargs.setdefault("seekable", False) - super().get_file(rpath, lpath, **kwargs) - - -@mirror_from( - "stream", - [ - "read", - "seek", - "tell", - "write", - "readable", - "writable", - "close", - "seekable", - ], -) -class ArrowFile(io.IOBase): - def __init__(self, fs, stream, path, mode, block_size=None, **kwargs): - self.path = path - self.mode = mode - - self.fs = fs - self.stream = stream - - self.blocksize = self.block_size = block_size - self.kwargs = kwargs - - def __enter__(self): - return self - - @property - def size(self): - if self.stream.seekable(): - return self.stream.size() - return None - - def __exit__(self, *args): - return self.close() - - -class HadoopFileSystem(ArrowFSWrapper): - """A wrapper on top of the pyarrow.fs.HadoopFileSystem - to connect it's interface with fsspec""" - - protocol = "hdfs" - - def __init__( - self, - host="default", - port=0, - user=None, - kerb_ticket=None, - replication=3, - extra_conf=None, - **kwargs, - ): - """ - - Parameters - ---------- - host: str - Hostname, IP or "default" to try to read from Hadoop config - port: int - Port to connect on, or default from Hadoop config if 0 - user: str or None - If given, connect as this username - kerb_ticket: str or None - If given, use this ticket for authentication - replication: int - set replication factor of file for write operations. default value is 3. - extra_conf: None or dict - Passed on to HadoopFileSystem - """ - from pyarrow.fs import HadoopFileSystem - - fs = HadoopFileSystem( - host=host, - port=port, - user=user, - kerb_ticket=kerb_ticket, - replication=replication, - extra_conf=extra_conf, - ) - super().__init__(fs=fs, **kwargs) - - @staticmethod - def _get_kwargs_from_urls(path): - ops = infer_storage_options(path) - out = {} - if ops.get("host", None): - out["host"] = ops["host"] - if ops.get("username", None): - out["user"] = ops["username"] - if ops.get("port", None): - out["port"] = ops["port"] - if ops.get("url_query", None): - queries = parse_qs(ops["url_query"]) - if queries.get("replication", None): - out["replication"] = int(queries["replication"][0]) - return out diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/asyn_wrapper.py b/venv/lib/python3.10/site-packages/fsspec/implementations/asyn_wrapper.py deleted file mode 100644 index 91db5eb48d00e36b46d9deb49504a7d2ad76d690..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/asyn_wrapper.py +++ /dev/null @@ -1,124 +0,0 @@ -import asyncio -import functools -import inspect - -import fsspec -from fsspec.asyn import AsyncFileSystem, running_async - -from .chained import ChainedFileSystem - - -def async_wrapper(func, obj=None, semaphore=None): - """ - Wraps a synchronous function to make it awaitable. - - Parameters - ---------- - func : callable - The synchronous function to wrap. - obj : object, optional - The instance to bind the function to, if applicable. - semaphore : asyncio.Semaphore, optional - A semaphore to limit concurrent calls. - - Returns - ------- - coroutine - An awaitable version of the function. - """ - - @functools.wraps(func) - async def wrapper(*args, **kwargs): - if semaphore: - async with semaphore: - return await asyncio.to_thread(func, *args, **kwargs) - return await asyncio.to_thread(func, *args, **kwargs) - - return wrapper - - -class AsyncFileSystemWrapper(AsyncFileSystem, ChainedFileSystem): - """ - A wrapper class to convert a synchronous filesystem into an asynchronous one. - - This class takes an existing synchronous filesystem implementation and wraps all - its methods to provide an asynchronous interface. - - Parameters - ---------- - sync_fs : AbstractFileSystem - The synchronous filesystem instance to wrap. - """ - - protocol = "asyncwrapper", "async_wrapper" - cachable = False - - def __init__( - self, - fs=None, - asynchronous=None, - target_protocol=None, - target_options=None, - semaphore=None, - max_concurrent_tasks=None, - **kwargs, - ): - if asynchronous is None: - asynchronous = running_async() - super().__init__(asynchronous=asynchronous, **kwargs) - if fs is not None: - self.sync_fs = fs - else: - self.sync_fs = fsspec.filesystem(target_protocol, **target_options) - self.protocol = self.sync_fs.protocol - self.semaphore = semaphore - self._wrap_all_sync_methods() - - @property - def fsid(self): - return f"async_{self.sync_fs.fsid}" - - def _wrap_all_sync_methods(self): - """ - Wrap all synchronous methods of the underlying filesystem with asynchronous versions. - """ - excluded_methods = {"open"} - for method_name in dir(self.sync_fs): - if method_name.startswith("_") or method_name in excluded_methods: - continue - - attr = inspect.getattr_static(self.sync_fs, method_name) - if isinstance(attr, property): - continue - - method = getattr(self.sync_fs, method_name) - if callable(method) and not inspect.iscoroutinefunction(method): - async_method = async_wrapper(method, obj=self, semaphore=self.semaphore) - setattr(self, f"_{method_name}", async_method) - - @classmethod - def wrap_class(cls, sync_fs_class): - """ - Create a new class that can be used to instantiate an AsyncFileSystemWrapper - with lazy instantiation of the underlying synchronous filesystem. - - Parameters - ---------- - sync_fs_class : type - The class of the synchronous filesystem to wrap. - - Returns - ------- - type - A new class that wraps the provided synchronous filesystem class. - """ - - class GeneratedAsyncFileSystemWrapper(cls): - def __init__(self, *args, **kwargs): - sync_fs = sync_fs_class(*args, **kwargs) - super().__init__(sync_fs) - - GeneratedAsyncFileSystemWrapper.__name__ = ( - f"Async{sync_fs_class.__name__}Wrapper" - ) - return GeneratedAsyncFileSystemWrapper diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/cache_mapper.py b/venv/lib/python3.10/site-packages/fsspec/implementations/cache_mapper.py deleted file mode 100644 index 6e7c7d88afdddf12f77b26bb635bd8bf1e2bd7f1..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/cache_mapper.py +++ /dev/null @@ -1,75 +0,0 @@ -from __future__ import annotations - -import abc -import hashlib - -from fsspec.implementations.local import make_path_posix - - -class AbstractCacheMapper(abc.ABC): - """Abstract super-class for mappers from remote URLs to local cached - basenames. - """ - - @abc.abstractmethod - def __call__(self, path: str) -> str: ... - - def __eq__(self, other: object) -> bool: - # Identity only depends on class. When derived classes have attributes - # they will need to be included. - return isinstance(other, type(self)) - - def __hash__(self) -> int: - # Identity only depends on class. When derived classes have attributes - # they will need to be included. - return hash(type(self)) - - -class BasenameCacheMapper(AbstractCacheMapper): - """Cache mapper that uses the basename of the remote URL and a fixed number - of directory levels above this. - - The default is zero directory levels, meaning different paths with the same - basename will have the same cached basename. - """ - - def __init__(self, directory_levels: int = 0): - if directory_levels < 0: - raise ValueError( - "BasenameCacheMapper requires zero or positive directory_levels" - ) - self.directory_levels = directory_levels - - # Separator for directories when encoded as strings. - self._separator = "_@_" - - def __call__(self, path: str) -> str: - path = make_path_posix(path) - prefix, *bits = path.rsplit("/", self.directory_levels + 1) - if bits: - return self._separator.join(bits) - else: - return prefix # No separator found, simple filename - - def __eq__(self, other: object) -> bool: - return super().__eq__(other) and self.directory_levels == other.directory_levels - - def __hash__(self) -> int: - return super().__hash__() ^ hash(self.directory_levels) - - -class HashCacheMapper(AbstractCacheMapper): - """Cache mapper that uses a hash of the remote URL.""" - - def __call__(self, path: str) -> str: - return hashlib.sha256(path.encode()).hexdigest() - - -def create_cache_mapper(same_names: bool) -> AbstractCacheMapper: - """Factory method to create cache mapper for backward compatibility with - ``CachingFileSystem`` constructor using ``same_names`` kwarg. - """ - if same_names: - return BasenameCacheMapper() - else: - return HashCacheMapper() diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/cache_metadata.py b/venv/lib/python3.10/site-packages/fsspec/implementations/cache_metadata.py deleted file mode 100644 index 9d1f7eb7f846186606921ff6a1539442a0899506..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/cache_metadata.py +++ /dev/null @@ -1,231 +0,0 @@ -from __future__ import annotations - -import os -import pickle -import time -from typing import TYPE_CHECKING - -from fsspec.utils import atomic_write - -try: - import ujson as json -except ImportError: - if not TYPE_CHECKING: - import json - -if TYPE_CHECKING: - from collections.abc import Iterator - from typing import Any, Literal, TypeAlias - - from .cached import CachingFileSystem - - Detail: TypeAlias = dict[str, Any] - - -class CacheMetadata: - """Cache metadata. - - All reading and writing of cache metadata is performed by this class, - accessing the cached files and blocks is not. - - Metadata is stored in a single file per storage directory in JSON format. - For backward compatibility, also reads metadata stored in pickle format - which is converted to JSON when next saved. - """ - - def __init__(self, storage: list[str]): - """ - - Parameters - ---------- - storage: list[str] - Directories containing cached files, must be at least one. Metadata - is stored in the last of these directories by convention. - """ - if not storage: - raise ValueError("CacheMetadata expects at least one storage location") - - self._storage = storage - self.cached_files: list[Detail] = [{}] - - # Private attribute to force saving of metadata in pickle format rather than - # JSON for use in tests to confirm can read both pickle and JSON formats. - self._force_save_pickle = False - - def _load(self, fn: str) -> Detail: - """Low-level function to load metadata from specific file""" - try: - with open(fn, "r") as f: - loaded = json.load(f) - except ValueError: - with open(fn, "rb") as f: - loaded = pickle.load(f) - for c in loaded.values(): - if isinstance(c.get("blocks"), list): - c["blocks"] = set(c["blocks"]) - return loaded - - def _save(self, metadata_to_save: Detail, fn: str) -> None: - """Low-level function to save metadata to specific file""" - if self._force_save_pickle: - with atomic_write(fn) as f: - pickle.dump(metadata_to_save, f) - else: - with atomic_write(fn, mode="w") as f: - json.dump(metadata_to_save, f) - - def _scan_locations( - self, writable_only: bool = False - ) -> Iterator[tuple[str, str, bool]]: - """Yield locations (filenames) where metadata is stored, and whether - writable or not. - - Parameters - ---------- - writable: bool - Set to True to only yield writable locations. - - Returns - ------- - Yields (str, str, bool) - """ - n = len(self._storage) - for i, storage in enumerate(self._storage): - writable = i == n - 1 - if writable_only and not writable: - continue - yield os.path.join(storage, "cache"), storage, writable - - def check_file( - self, path: str, cfs: CachingFileSystem | None - ) -> Literal[False] | tuple[Detail, str]: - """If path is in cache return its details, otherwise return ``False``. - - If the optional CachingFileSystem is specified then it is used to - perform extra checks to reject possible matches, such as if they are - too old. - """ - for (fn, base, _), cache in zip(self._scan_locations(), self.cached_files): - if path not in cache: - continue - detail = cache[path].copy() - - if cfs is not None: - if cfs.check_files and detail["uid"] != cfs.fs.ukey(path): - # Wrong file as determined by hash of file properties - continue - if cfs.expiry and time.time() - detail["time"] > cfs.expiry: - # Cached file has expired - continue - - fn = os.path.join(base, detail["fn"]) - if os.path.exists(fn): - return detail, fn - return False - - def clear_expired(self, expiry_time: int) -> tuple[list[str], bool]: - """Remove expired metadata from the cache. - - Returns names of files corresponding to expired metadata and a boolean - flag indicating whether the writable cache is empty. Caller is - responsible for deleting the expired files. - """ - expired_files = [] - for path, detail in self.cached_files[-1].copy().items(): - if time.time() - detail["time"] > expiry_time: - fn = detail.get("fn", "") - if not fn: - raise RuntimeError( - f"Cache metadata does not contain 'fn' for {path}" - ) - fn = os.path.join(self._storage[-1], fn) - expired_files.append(fn) - self.cached_files[-1].pop(path) - - if self.cached_files[-1]: - cache_path = os.path.join(self._storage[-1], "cache") - self._save(self.cached_files[-1], cache_path) - - writable_cache_empty = not self.cached_files[-1] - return expired_files, writable_cache_empty - - def load(self) -> None: - """Load all metadata from disk and store in ``self.cached_files``""" - cached_files = [] - for fn, _, _ in self._scan_locations(): - if os.path.exists(fn): - # TODO: consolidate blocks here - cached_files.append(self._load(fn)) - else: - cached_files.append({}) - self.cached_files = cached_files or [{}] - - def on_close_cached_file(self, f: Any, path: str) -> None: - """Perform side-effect actions on closing a cached file. - - The actual closing of the file is the responsibility of the caller. - """ - # File must be writeble, so in self.cached_files[-1] - c = self.cached_files[-1][path] - if c["blocks"] is not True and len(c["blocks"]) * f.blocksize >= f.size: - c["blocks"] = True - - def pop_file(self, path: str) -> str | None: - """Remove metadata of cached file. - - If path is in the cache, return the filename of the cached file, - otherwise return ``None``. Caller is responsible for deleting the - cached file. - """ - details = self.check_file(path, None) - if not details: - return None - _, fn = details - if fn.startswith(self._storage[-1]): - self.cached_files[-1].pop(path) - self.save() - else: - raise PermissionError( - "Can only delete cached file in last, writable cache location" - ) - return fn - - def save(self) -> None: - """Save metadata to disk""" - for (fn, _, writable), cache in zip(self._scan_locations(), self.cached_files): - if not writable: - continue - - if os.path.exists(fn): - cached_files = self._load(fn) - for k, c in cached_files.items(): - if k in cache: - if c["blocks"] is True or cache[k]["blocks"] is True: - c["blocks"] = True - else: - # self.cached_files[*][*]["blocks"] must continue to - # point to the same set object so that updates - # performed by MMapCache are propagated back to - # self.cached_files. - blocks = cache[k]["blocks"] - blocks.update(c["blocks"]) - c["blocks"] = blocks - c["time"] = max(c["time"], cache[k]["time"]) - c["uid"] = cache[k]["uid"] - - # Files can be added to cache after it was written once - for k, c in cache.items(): - if k not in cached_files: - cached_files[k] = c - else: - cached_files = cache - cache = {k: v.copy() for k, v in cached_files.items()} - for c in cache.values(): - if isinstance(c["blocks"], set): - c["blocks"] = list(c["blocks"]) - self._save(cache, fn) - self.cached_files[-1] = cached_files - - def update_file(self, path: str, detail: Detail) -> None: - """Update metadata for specific file in memory, do not save""" - self.cached_files[-1][path] = detail diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/cached.py b/venv/lib/python3.10/site-packages/fsspec/implementations/cached.py deleted file mode 100644 index 3f4fc0f662d6989da346a5e672e06466156f5f21..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/cached.py +++ /dev/null @@ -1,1021 +0,0 @@ -from __future__ import annotations - -import inspect -import logging -import os -import tempfile -import time -import weakref -from collections.abc import Callable -from shutil import rmtree -from typing import TYPE_CHECKING, Any, ClassVar - -from fsspec import filesystem -from fsspec.callbacks import DEFAULT_CALLBACK -from fsspec.compression import compr -from fsspec.core import BaseCache, MMapCache -from fsspec.exceptions import BlocksizeMismatchError -from fsspec.implementations.cache_mapper import create_cache_mapper -from fsspec.implementations.cache_metadata import CacheMetadata -from fsspec.implementations.chained import ChainedFileSystem -from fsspec.implementations.local import LocalFileSystem -from fsspec.spec import AbstractBufferedFile -from fsspec.transaction import Transaction -from fsspec.utils import infer_compression - -if TYPE_CHECKING: - from fsspec.implementations.cache_mapper import AbstractCacheMapper - -logger = logging.getLogger("fsspec.cached") - - -class WriteCachedTransaction(Transaction): - def complete(self, commit=True): - rpaths = [f.path for f in self.files] - lpaths = [f.fn for f in self.files] - if commit: - self.fs.put(lpaths, rpaths) - self.files.clear() - self.fs._intrans = False - self.fs._transaction = None - self.fs = None # break cycle - - -class CachingFileSystem(ChainedFileSystem): - """Locally caching filesystem, layer over any other FS - - This class implements chunk-wise local storage of remote files, for quick - access after the initial download. The files are stored in a given - directory with hashes of URLs for the filenames. If no directory is given, - a temporary one is used, which should be cleaned up by the OS after the - process ends. The files themselves are sparse (as implemented in - :class:`~fsspec.caching.MMapCache`), so only the data which is accessed - takes up space. - - Restrictions: - - - the block-size must be the same for each access of a given file, unless - all blocks of the file have already been read - - caching can only be applied to file-systems which produce files - derived from fsspec.spec.AbstractBufferedFile ; LocalFileSystem is also - allowed, for testing - """ - - protocol: ClassVar[str | tuple[str, ...]] = ("blockcache", "cached") - _strip_tokenize_options = ("fo",) - - def __init__( - self, - target_protocol=None, - cache_storage="TMP", - cache_check=10, - check_files=False, - expiry_time=604800, - target_options=None, - fs=None, - same_names: bool | None = None, - compression=None, - cache_mapper: AbstractCacheMapper | None = None, - **kwargs, - ): - """ - - Parameters - ---------- - target_protocol: str (optional) - Target filesystem protocol. Provide either this or ``fs``. - cache_storage: str or list(str) - Location to store files. If "TMP", this is a temporary directory, - and will be cleaned up by the OS when this process ends (or later). - If a list, each location will be tried in the order given, but - only the last will be considered writable. - cache_check: int - Number of seconds between reload of cache metadata - check_files: bool - Whether to explicitly see if the UID of the remote file matches - the stored one before using. Warning: some file systems such as - HTTP cannot reliably give a unique hash of the contents of some - path, so be sure to set this option to False. - expiry_time: int - The time in seconds after which a local copy is considered useless. - Set to falsy to prevent expiry. The default is equivalent to one - week. - target_options: dict or None - Passed to the instantiation of the FS, if fs is None. - fs: filesystem instance - The target filesystem to run against. Provide this or ``protocol``. - same_names: bool (optional) - By default, target URLs are hashed using a ``HashCacheMapper`` so - that files from different backends with the same basename do not - conflict. If this argument is ``true``, a ``BasenameCacheMapper`` - is used instead. Other cache mapper options are available by using - the ``cache_mapper`` keyword argument. Only one of this and - ``cache_mapper`` should be specified. - compression: str (optional) - To decompress on download. Can be 'infer' (guess from the URL name), - one of the entries in ``fsspec.compression.compr``, or None for no - decompression. - cache_mapper: AbstractCacheMapper (optional) - The object use to map from original filenames to cached filenames. - Only one of this and ``same_names`` should be specified. - """ - super().__init__(**kwargs) - if fs is None and target_protocol is None: - raise ValueError( - "Please provide filesystem instance(fs) or target_protocol" - ) - if not (fs is None) ^ (target_protocol is None): - raise ValueError( - "Both filesystems (fs) and target_protocol may not be both given." - ) - if cache_storage == "TMP": - tempdir = tempfile.mkdtemp() - storage = [tempdir] - weakref.finalize(self, self._remove_tempdir, tempdir) - else: - if isinstance(cache_storage, str): - storage = [cache_storage] - else: - storage = cache_storage - os.makedirs(storage[-1], exist_ok=True) - self.storage = storage - self.kwargs = target_options or {} - self.cache_check = cache_check - self.check_files = check_files - self.expiry = expiry_time - self.compression = compression - - # Size of cache in bytes. If None then the size is unknown and will be - # recalculated the next time cache_size() is called. On writes to the - # cache this is reset to None. - self._cache_size = None - - if same_names is not None and cache_mapper is not None: - raise ValueError( - "Cannot specify both same_names and cache_mapper in " - "CachingFileSystem.__init__" - ) - if cache_mapper is not None: - self._mapper = cache_mapper - else: - self._mapper = create_cache_mapper( - same_names if same_names is not None else False - ) - - self.target_protocol = ( - target_protocol - if isinstance(target_protocol, str) - else (fs.protocol if isinstance(fs.protocol, str) else fs.protocol[0]) - ) - self._metadata = CacheMetadata(self.storage) - self.load_cache() - self.fs = fs if fs is not None else filesystem(target_protocol, **self.kwargs) - - def _strip_protocol(path): - # acts as a method, since each instance has a difference target - return self.fs._strip_protocol(type(self)._strip_protocol(path)) - - self._strip_protocol: Callable = _strip_protocol - - @staticmethod - def _remove_tempdir(tempdir): - try: - rmtree(tempdir) - except Exception: - pass - - def _mkcache(self): - os.makedirs(self.storage[-1], exist_ok=True) - - def cache_size(self): - """Return size of cache in bytes. - - If more than one cache directory is in use, only the size of the last - one (the writable cache directory) is returned. - """ - if self._cache_size is None: - cache_dir = self.storage[-1] - self._cache_size = filesystem("file").du(cache_dir, withdirs=True) - return self._cache_size - - def load_cache(self): - """Read set of stored blocks from file""" - self._metadata.load() - self._mkcache() - self.last_cache = time.time() - - def save_cache(self): - """Save set of stored blocks from file""" - self._mkcache() - self._metadata.save() - self.last_cache = time.time() - self._cache_size = None - - def _check_cache(self): - """Reload caches if time elapsed or any disappeared""" - self._mkcache() - if not self.cache_check: - # explicitly told not to bother checking - return - timecond = time.time() - self.last_cache > self.cache_check - existcond = all(os.path.exists(storage) for storage in self.storage) - if timecond or not existcond: - self.load_cache() - - def _check_file(self, path): - """Is path in cache and still valid""" - path = self._strip_protocol(path) - self._check_cache() - return self._metadata.check_file(path, self) - - def clear_cache(self): - """Remove all files and metadata from the cache - - In the case of multiple cache locations, this clears only the last one, - which is assumed to be the read/write one. - """ - rmtree(self.storage[-1]) - self.load_cache() - self._cache_size = None - - def clear_expired_cache(self, expiry_time=None): - """Remove all expired files and metadata from the cache - - In the case of multiple cache locations, this clears only the last one, - which is assumed to be the read/write one. - - Parameters - ---------- - expiry_time: int - The time in seconds after which a local copy is considered useless. - If not defined the default is equivalent to the attribute from the - file caching instantiation. - """ - - if not expiry_time: - expiry_time = self.expiry - - self._check_cache() - - expired_files, writable_cache_empty = self._metadata.clear_expired(expiry_time) - for fn in expired_files: - if os.path.exists(fn): - os.remove(fn) - - if writable_cache_empty: - rmtree(self.storage[-1]) - self.load_cache() - - self._cache_size = None - - def pop_from_cache(self, path): - """Remove cached version of given file - - Deletes local copy of the given (remote) path. If it is found in a cache - location which is not the last, it is assumed to be read-only, and - raises PermissionError - """ - path = self._strip_protocol(path) - fn = self._metadata.pop_file(path) - if fn is not None: - os.remove(fn) - self._cache_size = None - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - **kwargs, - ): - """Wrap the target _open - - If the whole file exists in the cache, just open it locally and - return that. - - Otherwise, open the file on the target FS, and make it have a mmap - cache pointing to the location which we determine, in our cache. - The ``blocks`` instance is shared, so as the mmap cache instance - updates, so does the entry in our ``cached_files`` attribute. - We monkey-patch this file, so that when it closes, we call - ``close_and_update`` to save the state of the blocks. - """ - path = self._strip_protocol(path) - - path = self.fs._strip_protocol(path) - if "r" not in mode: - return self.fs._open( - path, - mode=mode, - block_size=block_size, - autocommit=autocommit, - cache_options=cache_options, - **kwargs, - ) - detail = self._check_file(path) - if detail: - # file is in cache - detail, fn = detail - hash, blocks = detail["fn"], detail["blocks"] - if blocks is True: - # stored file is complete - logger.debug("Opening local copy of %s", path) - return open(fn, mode) - # TODO: action where partial file exists in read-only cache - logger.debug("Opening partially cached copy of %s", path) - else: - hash = self._mapper(path) - fn = os.path.join(self.storage[-1], hash) - blocks = set() - detail = { - "original": path, - "fn": hash, - "blocks": blocks, - "time": time.time(), - "uid": self.fs.ukey(path), - } - self._metadata.update_file(path, detail) - logger.debug("Creating local sparse file for %s", path) - - # explicitly submitting the size to the open call will avoid extra - # operations when opening. This is particularly relevant - # for any file that is read over a network, e.g. S3. - size = detail.get("size") - - # call target filesystems open - self._mkcache() - f = self.fs._open( - path, - mode=mode, - block_size=block_size, - autocommit=autocommit, - cache_options=cache_options, - cache_type="none", - size=size, - **kwargs, - ) - - # set size if not already set - if size is None: - detail["size"] = f.size - self._metadata.update_file(path, detail) - - if self.compression: - comp = ( - infer_compression(path) - if self.compression == "infer" - else self.compression - ) - f = compr[comp](f, mode="rb") - if "blocksize" in detail: - if detail["blocksize"] != f.blocksize: - raise BlocksizeMismatchError( - f"Cached file must be reopened with same block" - f" size as original (old: {detail['blocksize']}," - f" new {f.blocksize})" - ) - else: - detail["blocksize"] = f.blocksize - - def _fetch_ranges(ranges): - return self.fs.cat_ranges( - [path] * len(ranges), - [r[0] for r in ranges], - [r[1] for r in ranges], - **kwargs, - ) - - multi_fetcher = None if self.compression else _fetch_ranges - f.cache = MMapCache( - f.blocksize, f._fetch_range, f.size, fn, blocks, multi_fetcher=multi_fetcher - ) - close = f.close - f.close = lambda: self.close_and_update(f, close) - self.save_cache() - return f - - def _parent(self, path): - return self.fs._parent(path) - - def hash_name(self, path: str, *args: Any) -> str: - # Kept for backward compatibility with downstream libraries. - # Ignores extra arguments, previously same_name boolean. - return self._mapper(path) - - def close_and_update(self, f, close): - """Called when a file is closing, so store the set of blocks""" - if f.closed: - return - path = self._strip_protocol(f.path) - self._metadata.on_close_cached_file(f, path) - try: - logger.debug("going to save") - self.save_cache() - logger.debug("saved") - except OSError: - logger.debug("Cache saving failed while closing file") - except NameError: - logger.debug("Cache save failed due to interpreter shutdown") - close() - f.closed = True - - def ls(self, path, detail=True): - return self.fs.ls(path, detail) - - def __getattribute__(self, item): - if item in { - "load_cache", - "_get_cached_file_before_open", - "_open", - "save_cache", - "close_and_update", - "__init__", - "__getattribute__", - "__reduce__", - "_make_local_details", - "open", - "cat", - "cat_file", - "_cat_file", - "cat_ranges", - "_cat_ranges", - "get", - "read_block", - "tail", - "head", - "info", - "ls", - "exists", - "isfile", - "isdir", - "_check_file", - "_check_cache", - "_mkcache", - "clear_cache", - "clear_expired_cache", - "pop_from_cache", - "local_file", - "_paths_from_path", - "get_mapper", - "open_many", - "commit_many", - "hash_name", - "__hash__", - "__eq__", - "to_json", - "to_dict", - "cache_size", - "pipe_file", - "pipe", - "start_transaction", - "end_transaction", - }: - # all the methods defined in this class. Note `open` here, since - # it calls `_open`, but is actually in superclass - return lambda *args, **kw: getattr(type(self), item).__get__(self)( - *args, **kw - ) - if item in ["__reduce_ex__"]: - raise AttributeError - if item in ["transaction"]: - # property - return type(self).transaction.__get__(self) - if item in {"_cache", "transaction_type", "protocol"}: - # class attributes - return getattr(type(self), item) - if item == "__class__": - return type(self) - d = object.__getattribute__(self, "__dict__") - fs = d.get("fs", None) # fs is not immediately defined - if item in d: - return d[item] - elif fs is not None: - if item in fs.__dict__: - # attribute of instance - return fs.__dict__[item] - # attributed belonging to the target filesystem - cls = type(fs) - m = getattr(cls, item) - if (inspect.isfunction(m) or inspect.isdatadescriptor(m)) and ( - not hasattr(m, "__self__") or m.__self__ is None - ): - # instance method - return m.__get__(fs, cls) - return m # class method or attribute - else: - # attributes of the superclass, while target is being set up - return super().__getattribute__(item) - - def __eq__(self, other): - """Test for equality.""" - if self is other: - return True - if not isinstance(other, type(self)): - return False - return ( - self.storage == other.storage - and self.kwargs == other.kwargs - and self.cache_check == other.cache_check - and self.check_files == other.check_files - and self.expiry == other.expiry - and self.compression == other.compression - and self._mapper == other._mapper - and self.target_protocol == other.target_protocol - ) - - def __hash__(self): - """Calculate hash.""" - return ( - hash(tuple(self.storage)) - ^ hash(str(self.kwargs)) - ^ hash(self.cache_check) - ^ hash(self.check_files) - ^ hash(self.expiry) - ^ hash(self.compression) - ^ hash(self._mapper) - ^ hash(self.target_protocol) - ) - - -class WholeFileCacheFileSystem(CachingFileSystem): - """Caches whole remote files on first access - - This class is intended as a layer over any other file system, and - will make a local copy of each file accessed, so that all subsequent - reads are local. This is similar to ``CachingFileSystem``, but without - the block-wise functionality and so can work even when sparse files - are not allowed. See its docstring for definition of the init - arguments. - - The class still needs access to the remote store for listing files, - and may refresh cached files. - """ - - protocol = "filecache" - local_file = True - - def open_many(self, open_files, **kwargs): - paths = [of.path for of in open_files] - if "r" in open_files.mode: - self._mkcache() - else: - return [ - LocalTempFile( - self.fs, - path, - mode=open_files.mode, - fn=os.path.join(self.storage[-1], self._mapper(path)), - **kwargs, - ) - for path in paths - ] - - if self.compression: - raise NotImplementedError - details = [self._check_file(sp) for sp in paths] - downpath = [p for p, d in zip(paths, details) if not d] - downfn0 = [ - os.path.join(self.storage[-1], self._mapper(p)) - for p, d in zip(paths, details) - ] # keep these path names for opening later - downfn = [fn for fn, d in zip(downfn0, details) if not d] - if downpath: - # skip if all files are already cached and up to date - self.fs.get(downpath, downfn) - - # update metadata - only happens when downloads are successful - newdetail = [ - { - "original": path, - "fn": self._mapper(path), - "blocks": True, - "time": time.time(), - "uid": self.fs.ukey(path), - } - for path in downpath - ] - for path, detail in zip(downpath, newdetail): - self._metadata.update_file(path, detail) - self.save_cache() - - def firstpart(fn): - # helper to adapt both whole-file and simple-cache - return fn[1] if isinstance(fn, tuple) else fn - - return [ - open(firstpart(fn0) if fn0 else fn1, mode=open_files.mode) - for fn0, fn1 in zip(details, downfn0) - ] - - def commit_many(self, open_files): - self.fs.put([f.fn for f in open_files], [f.path for f in open_files]) - [f.close() for f in open_files] - for f in open_files: - # in case autocommit is off, and so close did not already delete - try: - os.remove(f.name) - except FileNotFoundError: - pass - self._cache_size = None - - def _make_local_details(self, path): - hash = self._mapper(path) - fn = os.path.join(self.storage[-1], hash) - detail = { - "original": path, - "fn": hash, - "blocks": True, - "time": time.time(), - "uid": self.fs.ukey(path), - } - self._metadata.update_file(path, detail) - logger.debug("Copying %s to local cache", path) - return fn - - def cat( - self, - path, - recursive=False, - on_error="raise", - callback=DEFAULT_CALLBACK, - **kwargs, - ): - paths = self.expand_path( - path, recursive=recursive, maxdepth=kwargs.get("maxdepth") - ) - getpaths = [] - storepaths = [] - fns = [] - out = {} - for p in paths.copy(): - try: - detail = self._check_file(p) - if not detail: - fn = self._make_local_details(p) - getpaths.append(p) - storepaths.append(fn) - else: - detail, fn = detail if isinstance(detail, tuple) else (None, detail) - fns.append(fn) - except Exception as e: - if on_error == "raise": - raise - if on_error == "return": - out[p] = e - paths.remove(p) - - if getpaths: - self.fs.get(getpaths, storepaths) - self.save_cache() - - callback.set_size(len(paths)) - for p, fn in zip(paths, fns): - with open(fn, "rb") as f: - out[p] = f.read() - callback.relative_update(1) - if isinstance(path, str) and len(paths) == 1 and recursive is False: - out = out[paths[0]] - return out - - def _get_cached_file_before_open(self, path, **kwargs): - fn = self._make_local_details(path) - # call target filesystems open - self._mkcache() - if self.compression: - with self.fs._open(path, mode="rb", **kwargs) as f, open(fn, "wb") as f2: - if isinstance(f, AbstractBufferedFile): - # want no type of caching if just downloading whole thing - f.cache = BaseCache(0, f.cache.fetcher, f.size) - comp = ( - infer_compression(path) - if self.compression == "infer" - else self.compression - ) - f = compr[comp](f, mode="rb") - data = True - while data: - block = getattr(f, "blocksize", 5 * 2**20) - data = f.read(block) - f2.write(data) - else: - self.fs.get_file(path, fn) - self.save_cache() - - def _open(self, path, mode="rb", **kwargs): - path = self._strip_protocol(path) - # For read (or append), (try) download from remote - if "r" in mode or "a" in mode: - if not self._check_file(path): - if self.fs.exists(path): - self._get_cached_file_before_open(path, **kwargs) - elif "r" in mode: - raise FileNotFoundError(path) - - detail, fn = self._check_file(path) - _, blocks = detail["fn"], detail["blocks"] - if blocks is True: - logger.debug("Opening local copy of %s", path) - else: - raise ValueError( - f"Attempt to open partially cached file {path}" - f" as a wholly cached file" - ) - - # Just reading does not need special file handling - if "r" in mode and "+" not in mode: - # In order to support downstream filesystems to be able to - # infer the compression from the original filename, like - # the `TarFileSystem`, let's extend the `io.BufferedReader` - # fileobject protocol by adding a dedicated attribute - # `original`. - f = open(fn, mode) - f.original = detail.get("original") - return f - - hash = self._mapper(path) - fn = os.path.join(self.storage[-1], hash) - user_specified_kwargs = { - k: v - for k, v in kwargs.items() - # those kwargs were added by open(), we don't want them - if k not in ["autocommit", "block_size", "cache_options"] - } - return LocalTempFile(self, path, mode=mode, fn=fn, **user_specified_kwargs) - - -class SimpleCacheFileSystem(WholeFileCacheFileSystem): - """Caches whole remote files on first access - - This class is intended as a layer over any other file system, and - will make a local copy of each file accessed, so that all subsequent - reads are local. This implementation only copies whole files, and - does not keep any metadata about the download time or file details. - It is therefore safer to use in multi-threaded/concurrent situations. - - This is the only of the caching filesystems that supports write: you will - be given a real local open file, and upon close and commit, it will be - uploaded to the target filesystem; the writability or the target URL is - not checked until that time. - - """ - - protocol = "simplecache" - local_file = True - transaction_type = WriteCachedTransaction - - def __init__(self, **kwargs): - kw = kwargs.copy() - for key in ["cache_check", "expiry_time", "check_files"]: - kw[key] = False - super().__init__(**kw) - for storage in self.storage: - if not os.path.exists(storage): - os.makedirs(storage, exist_ok=True) - - def _check_file(self, path): - self._check_cache() - sha = self._mapper(path) - for storage in self.storage: - fn = os.path.join(storage, sha) - if os.path.exists(fn): - return fn - - def save_cache(self): - pass - - def load_cache(self): - pass - - def pipe_file(self, path, value=None, **kwargs): - if self._intrans: - with self.open(path, "wb") as f: - f.write(value) - else: - super().pipe_file(path, value) - - def ls(self, path, detail=True, **kwargs): - path = self._strip_protocol(path) - details = [] - try: - details = self.fs.ls( - path, detail=True, **kwargs - ).copy() # don't edit original! - except FileNotFoundError as e: - ex = e - else: - ex = None - if self._intrans: - path1 = path.rstrip("/") + "/" - for f in self.transaction.files: - if f.path == path: - details.append( - {"name": path, "size": f.size or f.tell(), "type": "file"} - ) - elif f.path.startswith(path1): - if f.path.count("/") == path1.count("/"): - details.append( - {"name": f.path, "size": f.size or f.tell(), "type": "file"} - ) - else: - dname = "/".join(f.path.split("/")[: path1.count("/") + 1]) - details.append({"name": dname, "size": 0, "type": "directory"}) - if ex is not None and not details: - raise ex - if detail: - return details - return sorted(_["name"] for _ in details) - - def info(self, path, **kwargs): - path = self._strip_protocol(path) - if self._intrans: - f = [_ for _ in self.transaction.files if _.path == path] - if f: - size = os.path.getsize(f[0].fn) if f[0].closed else f[0].tell() - return {"name": path, "size": size, "type": "file"} - f = any(_.path.startswith(path + "/") for _ in self.transaction.files) - if f: - return {"name": path, "size": 0, "type": "directory"} - return self.fs.info(path, **kwargs) - - def pipe(self, path, value=None, **kwargs): - if isinstance(path, str): - self.pipe_file(self._strip_protocol(path), value, **kwargs) - elif isinstance(path, dict): - for k, v in path.items(): - self.pipe_file(self._strip_protocol(k), v, **kwargs) - else: - raise ValueError("path must be str or dict") - - async def _cat_file(self, path, start=None, end=None, **kwargs): - logger.debug("async cat_file %s", path) - path = self._strip_protocol(path) - sha = self._mapper(path) - fn = self._check_file(path) - - if not fn: - fn = os.path.join(self.storage[-1], sha) - await self.fs._get_file(path, fn, **kwargs) - - with open(fn, "rb") as f: # noqa ASYNC230 - if start: - f.seek(start) - size = -1 if end is None else end - f.tell() - return f.read(size) - - async def _cat_ranges( - self, paths, starts, ends, max_gap=None, on_error="return", **kwargs - ): - logger.debug("async cat ranges %s", paths) - lpaths = [] - rset = set() - download = [] - rpaths = [] - for p in paths: - fn = self._check_file(p) - if fn is None and p not in rset: - sha = self._mapper(p) - fn = os.path.join(self.storage[-1], sha) - download.append(fn) - rset.add(p) - rpaths.append(p) - lpaths.append(fn) - if download: - await self.fs._get(rpaths, download, on_error=on_error) - - return LocalFileSystem().cat_ranges( - lpaths, starts, ends, max_gap=max_gap, on_error=on_error, **kwargs - ) - - def cat_ranges( - self, paths, starts, ends, max_gap=None, on_error="return", **kwargs - ): - logger.debug("cat ranges %s", paths) - lpaths = [self._check_file(p) for p in paths] - rpaths = [p for l, p in zip(lpaths, paths) if l is False] - lpaths = [l for l, p in zip(lpaths, paths) if l is False] - self.fs.get(rpaths, lpaths) - paths = [self._check_file(p) for p in paths] - return LocalFileSystem().cat_ranges( - paths, starts, ends, max_gap=max_gap, on_error=on_error, **kwargs - ) - - def _get_cached_file_before_open(self, path, **kwargs): - sha = self._mapper(path) - fn = os.path.join(self.storage[-1], sha) - logger.debug("Copying %s to local cache", path) - - self._mkcache() - self._cache_size = None - - if self.compression: - with self.fs._open(path, mode="rb", **kwargs) as f, open(fn, "wb") as f2: - if isinstance(f, AbstractBufferedFile): - # want no type of caching if just downloading whole thing - f.cache = BaseCache(0, f.cache.fetcher, f.size) - comp = ( - infer_compression(path) - if self.compression == "infer" - else self.compression - ) - f = compr[comp](f, mode="rb") - data = True - while data: - block = getattr(f, "blocksize", 5 * 2**20) - data = f.read(block) - f2.write(data) - else: - self.fs.get_file(path, fn) - - def _open(self, path, mode="rb", **kwargs): - path = self._strip_protocol(path) - sha = self._mapper(path) - - # For read (or append), (try) download from remote - if "r" in mode or "a" in mode: - if not self._check_file(path): - # append does not require an existing file but read does - if self.fs.exists(path): - self._get_cached_file_before_open(path, **kwargs) - elif "r" in mode: - raise FileNotFoundError(path) - - fn = self._check_file(path) - # Just reading does not need special file handling - if "r" in mode and "+" not in mode: - return open(fn, mode) - - fn = os.path.join(self.storage[-1], sha) - user_specified_kwargs = { - k: v - for k, v in kwargs.items() - if k not in ["autocommit", "block_size", "cache_options"] - } # those were added by open() - return LocalTempFile( - self, - path, - mode=mode, - autocommit=not self._intrans, - fn=fn, - **user_specified_kwargs, - ) - - -class LocalTempFile: - """A temporary local file, which will be uploaded on commit""" - - def __init__(self, fs, path, fn, mode="wb", autocommit=True, seek=0, **kwargs): - self.fn = fn - self.fh = open(fn, mode) - self.mode = mode - if seek: - self.fh.seek(seek) - self.path = path - self.size = None - self.fs = fs - self.closed = False - self.autocommit = autocommit - self.kwargs = kwargs - - def __reduce__(self): - # always open in r+b to allow continuing writing at a location - return ( - LocalTempFile, - (self.fs, self.path, self.fn, "r+b", self.autocommit, self.tell()), - ) - - def __enter__(self): - return self.fh - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - - def close(self): - # self.size = self.fh.tell() - if self.closed: - return - self.fh.close() - self.closed = True - if self.autocommit: - self.commit() - - def discard(self): - self.fh.close() - os.remove(self.fn) - - def commit(self): - # calling put() with list arguments avoids path expansion and additional operations - # like isdir() - self.fs.put([self.fn], [self.path], **self.kwargs) - # we do not delete the local copy, it's still in the cache. - - @property - def name(self): - return self.fn - - def __repr__(self) -> str: - return f"LocalTempFile: {self.path}" - - def __getattr__(self, item): - return getattr(self.fh, item) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/chained.py b/venv/lib/python3.10/site-packages/fsspec/implementations/chained.py deleted file mode 100644 index bfce64334e8db0272eefa96b4428b23524b059f0..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/chained.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import ClassVar - -from fsspec import AbstractFileSystem - -__all__ = ("ChainedFileSystem",) - - -class ChainedFileSystem(AbstractFileSystem): - """Chained filesystem base class. - - A chained filesystem is designed to be layered over another FS. - This is useful to implement things like caching. - - This base class does very little on its own, but is used as a marker - that the class is designed for chaining. - - Right now this is only used in `url_to_fs` to provide the path argument - (`fo`) to the chained filesystem from the underlying filesystem. - - Additional functionality may be added in the future. - """ - - protocol: ClassVar[str] = "chained" diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/dask.py b/venv/lib/python3.10/site-packages/fsspec/implementations/dask.py deleted file mode 100644 index 3e1276463db6866665e6a0fe114efc247971b57e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/dask.py +++ /dev/null @@ -1,152 +0,0 @@ -import dask -from distributed.client import Client, _get_global_client -from distributed.worker import Worker - -from fsspec import filesystem -from fsspec.spec import AbstractBufferedFile, AbstractFileSystem -from fsspec.utils import infer_storage_options - - -def _get_client(client): - if client is None: - return _get_global_client() - elif isinstance(client, Client): - return client - else: - # e.g., connection string - return Client(client) - - -def _in_worker(): - return bool(Worker._instances) - - -class DaskWorkerFileSystem(AbstractFileSystem): - """View files accessible to a worker as any other remote file-system - - When instances are run on the worker, uses the real filesystem. When - run on the client, they call the worker to provide information or data. - - **Warning** this implementation is experimental, and read-only for now. - """ - - def __init__( - self, target_protocol=None, target_options=None, fs=None, client=None, **kwargs - ): - super().__init__(**kwargs) - if not (fs is None) ^ (target_protocol is None): - raise ValueError( - "Please provide one of filesystem instance (fs) or" - " target_protocol, not both" - ) - self.target_protocol = target_protocol - self.target_options = target_options - self.worker = None - self.client = client - self.fs = fs - self._determine_worker() - - @staticmethod - def _get_kwargs_from_urls(path): - so = infer_storage_options(path) - if "host" in so and "port" in so: - return {"client": f"{so['host']}:{so['port']}"} - else: - return {} - - def _determine_worker(self): - if _in_worker(): - self.worker = True - if self.fs is None: - self.fs = filesystem( - self.target_protocol, **(self.target_options or {}) - ) - else: - self.worker = False - self.client = _get_client(self.client) - self.rfs = dask.delayed(self) - - def mkdir(self, *args, **kwargs): - if self.worker: - self.fs.mkdir(*args, **kwargs) - else: - self.rfs.mkdir(*args, **kwargs).compute() - - def rm(self, *args, **kwargs): - if self.worker: - self.fs.rm(*args, **kwargs) - else: - self.rfs.rm(*args, **kwargs).compute() - - def copy(self, *args, **kwargs): - if self.worker: - self.fs.copy(*args, **kwargs) - else: - self.rfs.copy(*args, **kwargs).compute() - - def mv(self, *args, **kwargs): - if self.worker: - self.fs.mv(*args, **kwargs) - else: - self.rfs.mv(*args, **kwargs).compute() - - def ls(self, *args, **kwargs): - if self.worker: - return self.fs.ls(*args, **kwargs) - else: - return self.rfs.ls(*args, **kwargs).compute() - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - **kwargs, - ): - if self.worker: - return self.fs._open( - path, - mode=mode, - block_size=block_size, - autocommit=autocommit, - cache_options=cache_options, - **kwargs, - ) - else: - return DaskFile( - fs=self, - path=path, - mode=mode, - block_size=block_size, - autocommit=autocommit, - cache_options=cache_options, - **kwargs, - ) - - def fetch_range(self, path, mode, start, end): - if self.worker: - with self._open(path, mode) as f: - f.seek(start) - return f.read(end - start) - else: - return self.rfs.fetch_range(path, mode, start, end).compute() - - -class DaskFile(AbstractBufferedFile): - def __init__(self, mode="rb", **kwargs): - if mode != "rb": - raise ValueError('Remote dask files can only be opened in "rb" mode') - super().__init__(**kwargs) - - def _upload_chunk(self, final=False): - pass - - def _initiate_upload(self): - """Create remote file/upload""" - pass - - def _fetch_range(self, start, end): - """Get the specified set of bytes from remote""" - return self.fs.fetch_range(self.path, self.mode, start, end) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/data.py b/venv/lib/python3.10/site-packages/fsspec/implementations/data.py deleted file mode 100644 index f11542b48c98fd53fc367ade7425a00b38487619..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/data.py +++ /dev/null @@ -1,57 +0,0 @@ -import base64 -import io -from urllib.parse import unquote - -from fsspec import AbstractFileSystem - - -class DataFileSystem(AbstractFileSystem): - """A handy decoder for data-URLs - - Example - ------- - >>> with fsspec.open("data:,Hello%2C%20World%21") as f: - ... print(f.read()) - b"Hello, World!" - - See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs - """ - - protocol = "data" - - def __init__(self, **kwargs): - """No parameters for this filesystem""" - super().__init__(**kwargs) - - def cat_file(self, path, start=None, end=None, **kwargs): - pref, data = path.split(",", 1) - if pref.endswith("base64"): - return base64.b64decode(data)[start:end] - return unquote(data).encode()[start:end] - - def info(self, path, **kwargs): - pref, name = path.split(",", 1) - data = self.cat_file(path) - mime = pref.split(":", 1)[1].split(";", 1)[0] - return {"name": name, "size": len(data), "type": "file", "mimetype": mime} - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - **kwargs, - ): - if "r" not in mode: - raise ValueError("Read only filesystem") - return io.BytesIO(self.cat_file(path)) - - @staticmethod - def encode(data: bytes, mime: str | None = None): - """Format the given data into data-URL syntax - - This version always base64 encodes, even when the data is ascii/url-safe. - """ - return f"data:{mime or ''};base64,{base64.b64encode(data).decode()}" diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/dbfs.py b/venv/lib/python3.10/site-packages/fsspec/implementations/dbfs.py deleted file mode 100644 index 1a7fc93d7389c894ecb5fc6267ce20abe4087068..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/dbfs.py +++ /dev/null @@ -1,496 +0,0 @@ -from __future__ import annotations - -import base64 -import urllib - -import requests -from requests.adapters import HTTPAdapter, Retry -from typing_extensions import override - -from fsspec import AbstractFileSystem -from fsspec.spec import AbstractBufferedFile - - -class DatabricksException(Exception): - """ - Helper class for exceptions raised in this module. - """ - - def __init__(self, error_code, message, details=None): - """Create a new DatabricksException""" - super().__init__(message) - - self.error_code = error_code - self.message = message - self.details = details - - -class DatabricksFileSystem(AbstractFileSystem): - """ - Get access to the Databricks filesystem implementation over HTTP. - Can be used inside and outside of a databricks cluster. - """ - - def __init__(self, instance, token, **kwargs): - """ - Create a new DatabricksFileSystem. - - Parameters - ---------- - instance: str - The instance URL of the databricks cluster. - For example for an Azure databricks cluster, this - has the form adb-..azuredatabricks.net. - token: str - Your personal token. Find out more - here: https://docs.databricks.com/dev-tools/api/latest/authentication.html - """ - self.instance = instance - self.token = token - self.session = requests.Session() - self.retries = Retry( - total=10, - backoff_factor=0.05, - status_forcelist=[408, 429, 500, 502, 503, 504], - ) - - self.session.mount("https://", HTTPAdapter(max_retries=self.retries)) - self.session.headers.update({"Authorization": f"Bearer {self.token}"}) - - super().__init__(**kwargs) - - @override - def _ls_from_cache(self, path) -> list[dict[str, str | int]] | None: - """Check cache for listing - - Returns listing, if found (may be empty list for a directory that - exists but contains nothing), None if not in cache. - """ - self.dircache.pop(path.rstrip("/"), None) - - parent = self._parent(path) - if parent in self.dircache: - for entry in self.dircache[parent]: - if entry["name"] == path.rstrip("/"): - if entry["type"] != "directory": - return [entry] - return [] - raise FileNotFoundError(path) - - def ls(self, path, detail=True, **kwargs): - """ - List the contents of the given path. - - Parameters - ---------- - path: str - Absolute path - detail: bool - Return not only the list of filenames, - but also additional information on file sizes - and types. - """ - try: - out = self._ls_from_cache(path) - except FileNotFoundError: - # This happens if the `path`'s parent was cached, but `path` is not - # there. This suggests that `path` is new since the parent was - # cached. Attempt to invalidate parent's cache before continuing. - self.dircache.pop(self._parent(path), None) - out = None - - if not out: - try: - r = self._send_to_api( - method="get", endpoint="list", json={"path": path} - ) - except DatabricksException as e: - if e.error_code == "RESOURCE_DOES_NOT_EXIST": - raise FileNotFoundError(e.message) from e - - raise - files = r.get("files", []) - out = [ - { - "name": o["path"], - "type": "directory" if o["is_dir"] else "file", - "size": o["file_size"], - } - for o in files - ] - self.dircache[path] = out - - if detail: - return out - return [o["name"] for o in out] - - def makedirs(self, path, exist_ok=True): - """ - Create a given absolute path and all of its parents. - - Parameters - ---------- - path: str - Absolute path to create - exist_ok: bool - If false, checks if the folder - exists before creating it (and raises an - Exception if this is the case) - """ - if not exist_ok: - try: - # If the following succeeds, the path is already present - self._send_to_api( - method="get", endpoint="get-status", json={"path": path} - ) - raise FileExistsError(f"Path {path} already exists") - except DatabricksException as e: - if e.error_code == "RESOURCE_DOES_NOT_EXIST": - pass - - try: - self._send_to_api(method="post", endpoint="mkdirs", json={"path": path}) - except DatabricksException as e: - if e.error_code == "RESOURCE_ALREADY_EXISTS": - raise FileExistsError(e.message) from e - - raise - self.invalidate_cache(self._parent(path)) - - def mkdir(self, path, create_parents=True, **kwargs): - """ - Create a given absolute path and all of its parents. - - Parameters - ---------- - path: str - Absolute path to create - create_parents: bool - Whether to create all parents or not. - "False" is not implemented so far. - """ - if not create_parents: - raise NotImplementedError - - self.mkdirs(path, **kwargs) - - def rm(self, path, recursive=False, **kwargs): - """ - Remove the file or folder at the given absolute path. - - Parameters - ---------- - path: str - Absolute path what to remove - recursive: bool - Recursively delete all files in a folder. - """ - try: - self._send_to_api( - method="post", - endpoint="delete", - json={"path": path, "recursive": recursive}, - ) - except DatabricksException as e: - # This is not really an exception, it just means - # not everything was deleted so far - if e.error_code == "PARTIAL_DELETE": - self.rm(path=path, recursive=recursive) - elif e.error_code == "IO_ERROR": - # Using the same exception as the os module would use here - raise OSError(e.message) from e - - raise - self.invalidate_cache(self._parent(path)) - - def mv( - self, source_path, destination_path, recursive=False, maxdepth=None, **kwargs - ): - """ - Move a source to a destination path. - - A note from the original [databricks API manual] - (https://docs.databricks.com/dev-tools/api/latest/dbfs.html#move). - - When moving a large number of files the API call will time out after - approximately 60s, potentially resulting in partially moved data. - Therefore, for operations that move more than 10k files, we strongly - discourage using the DBFS REST API. - - Parameters - ---------- - source_path: str - From where to move (absolute path) - destination_path: str - To where to move (absolute path) - recursive: bool - Not implemented to far. - maxdepth: - Not implemented to far. - """ - if recursive: - raise NotImplementedError - if maxdepth: - raise NotImplementedError - - try: - self._send_to_api( - method="post", - endpoint="move", - json={"source_path": source_path, "destination_path": destination_path}, - ) - except DatabricksException as e: - if e.error_code == "RESOURCE_DOES_NOT_EXIST": - raise FileNotFoundError(e.message) from e - elif e.error_code == "RESOURCE_ALREADY_EXISTS": - raise FileExistsError(e.message) from e - - raise - self.invalidate_cache(self._parent(source_path)) - self.invalidate_cache(self._parent(destination_path)) - - def _open(self, path, mode="rb", block_size="default", **kwargs): - """ - Overwrite the base class method to make sure to create a DBFile. - All arguments are copied from the base method. - - Only the default blocksize is allowed. - """ - return DatabricksFile(self, path, mode=mode, block_size=block_size, **kwargs) - - def _send_to_api(self, method, endpoint, json): - """ - Send the given json to the DBFS API - using a get or post request (specified by the argument `method`). - - Parameters - ---------- - method: str - Which http method to use for communication; "get" or "post". - endpoint: str - Where to send the request to (last part of the API URL) - json: dict - Dictionary of information to send - """ - if method == "post": - session_call = self.session.post - elif method == "get": - session_call = self.session.get - else: - raise ValueError(f"Do not understand method {method}") - - url = urllib.parse.urljoin(f"https://{self.instance}/api/2.0/dbfs/", endpoint) - - r = session_call(url, json=json) - - # The DBFS API will return a json, also in case of an exception. - # We want to preserve this information as good as possible. - try: - r.raise_for_status() - except requests.HTTPError as e: - # try to extract json error message - # if that fails, fall back to the original exception - try: - exception_json = e.response.json() - except Exception: - raise e from None - - raise DatabricksException(**exception_json) from e - - return r.json() - - def _create_handle(self, path, overwrite=True): - """ - Internal function to create a handle, which can be used to - write blocks of a file to DBFS. - A handle has a unique identifier which needs to be passed - whenever written during this transaction. - The handle is active for 10 minutes - after that a new - write transaction needs to be created. - Make sure to close the handle after you are finished. - - Parameters - ---------- - path: str - Absolute path for this file. - overwrite: bool - If a file already exist at this location, either overwrite - it or raise an exception. - """ - try: - r = self._send_to_api( - method="post", - endpoint="create", - json={"path": path, "overwrite": overwrite}, - ) - return r["handle"] - except DatabricksException as e: - if e.error_code == "RESOURCE_ALREADY_EXISTS": - raise FileExistsError(e.message) from e - - raise - - def _close_handle(self, handle): - """ - Close a handle, which was opened by :func:`_create_handle`. - - Parameters - ---------- - handle: str - Which handle to close. - """ - try: - self._send_to_api(method="post", endpoint="close", json={"handle": handle}) - except DatabricksException as e: - if e.error_code == "RESOURCE_DOES_NOT_EXIST": - raise FileNotFoundError(e.message) from e - - raise - - def _add_data(self, handle, data): - """ - Upload data to an already opened file handle - (opened by :func:`_create_handle`). - The maximal allowed data size is 1MB after - conversion to base64. - Remember to close the handle when you are finished. - - Parameters - ---------- - handle: str - Which handle to upload data to. - data: bytes - Block of data to add to the handle. - """ - data = base64.b64encode(data).decode() - try: - self._send_to_api( - method="post", - endpoint="add-block", - json={"handle": handle, "data": data}, - ) - except DatabricksException as e: - if e.error_code == "RESOURCE_DOES_NOT_EXIST": - raise FileNotFoundError(e.message) from e - elif e.error_code == "MAX_BLOCK_SIZE_EXCEEDED": - raise ValueError(e.message) from e - - raise - - def _get_data(self, path, start, end): - """ - Download data in bytes from a given absolute path in a block - from [start, start+length]. - The maximum number of allowed bytes to read is 1MB. - - Parameters - ---------- - path: str - Absolute path to download data from - start: int - Start position of the block - end: int - End position of the block - """ - try: - r = self._send_to_api( - method="get", - endpoint="read", - json={"path": path, "offset": start, "length": end - start}, - ) - return base64.b64decode(r["data"]) - except DatabricksException as e: - if e.error_code == "RESOURCE_DOES_NOT_EXIST": - raise FileNotFoundError(e.message) from e - elif e.error_code in ["INVALID_PARAMETER_VALUE", "MAX_READ_SIZE_EXCEEDED"]: - raise ValueError(e.message) from e - - raise - - def invalidate_cache(self, path=None): - if path is None: - self.dircache.clear() - else: - self.dircache.pop(path, None) - super().invalidate_cache(path) - - -class DatabricksFile(AbstractBufferedFile): - """ - Helper class for files referenced in the DatabricksFileSystem. - """ - - DEFAULT_BLOCK_SIZE = 1 * 2**20 # only allowed block size - - def __init__( - self, - fs, - path, - mode="rb", - block_size="default", - autocommit=True, - cache_type="readahead", - cache_options=None, - **kwargs, - ): - """ - Create a new instance of the DatabricksFile. - - The blocksize needs to be the default one. - """ - if block_size is None or block_size == "default": - block_size = self.DEFAULT_BLOCK_SIZE - - assert block_size == self.DEFAULT_BLOCK_SIZE, ( - f"Only the default block size is allowed, not {block_size}" - ) - - super().__init__( - fs, - path, - mode=mode, - block_size=block_size, - autocommit=autocommit, - cache_type=cache_type, - cache_options=cache_options or {}, - **kwargs, - ) - - def _initiate_upload(self): - """Internal function to start a file upload""" - self.handle = self.fs._create_handle(self.path) - - def _upload_chunk(self, final=False): - """Internal function to add a chunk of data to a started upload""" - self.buffer.seek(0) - data = self.buffer.getvalue() - - data_chunks = [ - data[start:end] for start, end in self._to_sized_blocks(len(data)) - ] - - for data_chunk in data_chunks: - self.fs._add_data(handle=self.handle, data=data_chunk) - - if final: - self.fs._close_handle(handle=self.handle) - return True - - def _fetch_range(self, start, end): - """Internal function to download a block of data""" - return_buffer = b"" - length = end - start - for chunk_start, chunk_end in self._to_sized_blocks(length, start): - return_buffer += self.fs._get_data( - path=self.path, start=chunk_start, end=chunk_end - ) - - return return_buffer - - def _to_sized_blocks(self, length, start=0): - """Helper function to split a range from 0 to total_length into blocksizes""" - end = start + length - for data_chunk in range(start, end, self.blocksize): - data_start = data_chunk - data_end = min(end, data_chunk + self.blocksize) - yield data_start, data_end diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/dirfs.py b/venv/lib/python3.10/site-packages/fsspec/implementations/dirfs.py deleted file mode 100644 index 0f3dd3cf4c2f421292ba5d9fab8b733a60550496..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/dirfs.py +++ /dev/null @@ -1,389 +0,0 @@ -from .. import filesystem -from ..asyn import AsyncFileSystem -from .chained import ChainedFileSystem - - -class DirFileSystem(AsyncFileSystem, ChainedFileSystem): - """Directory prefix filesystem - - The DirFileSystem is a filesystem-wrapper. It assumes every path it is dealing with - is relative to the `path`. After performing the necessary paths operation it - delegates everything to the wrapped filesystem. - """ - - protocol = "dir" - - def __init__( - self, - path=None, - fs=None, - fo=None, - target_protocol=None, - target_options=None, - **storage_options, - ): - """ - Parameters - ---------- - path: str - Path to the directory. - fs: AbstractFileSystem - An instantiated filesystem to wrap. - target_protocol, target_options: - if fs is none, construct it from these - fo: str - Alternate for path; do not provide both - """ - super().__init__(**storage_options) - if fs is None: - fs = filesystem(protocol=target_protocol, **(target_options or {})) - path = path or fo - - if self.asynchronous and not fs.async_impl: - raise ValueError("can't use asynchronous with non-async fs") - - if fs.async_impl and self.asynchronous != fs.asynchronous: - raise ValueError("both dirfs and fs should be in the same sync/async mode") - - self.path = fs._strip_protocol(path) - self.fs = fs - - def _join(self, path): - if isinstance(path, str): - if not self.path: - return path - if not path: - return self.path - return self.fs.sep.join((self.path, self._strip_protocol(path))) - if isinstance(path, dict): - return {self._join(_path): value for _path, value in path.items()} - return [self._join(_path) for _path in path] - - def _relpath(self, path): - if isinstance(path, str): - if not self.path: - return path - # We need to account for S3FileSystem returning paths that do not - # start with a '/' - if path == self.path or ( - self.path.startswith(self.fs.sep) and path == self.path[1:] - ): - return "" - prefix = self.path + self.fs.sep - if self.path.startswith(self.fs.sep) and not path.startswith(self.fs.sep): - prefix = prefix[1:] - assert path.startswith(prefix) - return path[len(prefix) :] - return [self._relpath(_path) for _path in path] - - # Wrappers below - - @property - def sep(self): - return self.fs.sep - - async def set_session(self, *args, **kwargs): - return await self.fs.set_session(*args, **kwargs) - - async def _rm_file(self, path, **kwargs): - return await self.fs._rm_file(self._join(path), **kwargs) - - def rm_file(self, path, **kwargs): - return self.fs.rm_file(self._join(path), **kwargs) - - async def _rm(self, path, *args, **kwargs): - return await self.fs._rm(self._join(path), *args, **kwargs) - - def rm(self, path, *args, **kwargs): - return self.fs.rm(self._join(path), *args, **kwargs) - - async def _cp_file(self, path1, path2, **kwargs): - return await self.fs._cp_file(self._join(path1), self._join(path2), **kwargs) - - def cp_file(self, path1, path2, **kwargs): - return self.fs.cp_file(self._join(path1), self._join(path2), **kwargs) - - async def _copy( - self, - path1, - path2, - *args, - **kwargs, - ): - return await self.fs._copy( - self._join(path1), - self._join(path2), - *args, - **kwargs, - ) - - def copy(self, path1, path2, *args, **kwargs): - return self.fs.copy( - self._join(path1), - self._join(path2), - *args, - **kwargs, - ) - - async def _pipe(self, path, *args, **kwargs): - return await self.fs._pipe(self._join(path), *args, **kwargs) - - def pipe(self, path, *args, **kwargs): - return self.fs.pipe(self._join(path), *args, **kwargs) - - async def _pipe_file(self, path, *args, **kwargs): - return await self.fs._pipe_file(self._join(path), *args, **kwargs) - - def pipe_file(self, path, *args, **kwargs): - return self.fs.pipe_file(self._join(path), *args, **kwargs) - - async def _cat_file(self, path, *args, **kwargs): - return await self.fs._cat_file(self._join(path), *args, **kwargs) - - def cat_file(self, path, *args, **kwargs): - return self.fs.cat_file(self._join(path), *args, **kwargs) - - async def _cat(self, path, *args, **kwargs): - ret = await self.fs._cat( - self._join(path), - *args, - **kwargs, - ) - - if isinstance(ret, dict): - return {self._relpath(key): value for key, value in ret.items()} - - return ret - - def cat(self, path, *args, **kwargs): - ret = self.fs.cat( - self._join(path), - *args, - **kwargs, - ) - - if isinstance(ret, dict): - return {self._relpath(key): value for key, value in ret.items()} - - return ret - - async def _put_file(self, lpath, rpath, **kwargs): - return await self.fs._put_file(lpath, self._join(rpath), **kwargs) - - def put_file(self, lpath, rpath, **kwargs): - return self.fs.put_file(lpath, self._join(rpath), **kwargs) - - async def _put( - self, - lpath, - rpath, - *args, - **kwargs, - ): - return await self.fs._put( - lpath, - self._join(rpath), - *args, - **kwargs, - ) - - def put(self, lpath, rpath, *args, **kwargs): - return self.fs.put( - lpath, - self._join(rpath), - *args, - **kwargs, - ) - - async def _get_file(self, rpath, lpath, **kwargs): - return await self.fs._get_file(self._join(rpath), lpath, **kwargs) - - def get_file(self, rpath, lpath, **kwargs): - return self.fs.get_file(self._join(rpath), lpath, **kwargs) - - async def _get(self, rpath, *args, **kwargs): - return await self.fs._get(self._join(rpath), *args, **kwargs) - - def get(self, rpath, *args, **kwargs): - return self.fs.get(self._join(rpath), *args, **kwargs) - - async def _isfile(self, path): - return await self.fs._isfile(self._join(path)) - - def isfile(self, path): - return self.fs.isfile(self._join(path)) - - async def _isdir(self, path): - return await self.fs._isdir(self._join(path)) - - def isdir(self, path): - return self.fs.isdir(self._join(path)) - - async def _size(self, path): - return await self.fs._size(self._join(path)) - - def size(self, path): - return self.fs.size(self._join(path)) - - async def _exists(self, path): - return await self.fs._exists(self._join(path)) - - def exists(self, path): - return self.fs.exists(self._join(path)) - - async def _info(self, path, **kwargs): - info = await self.fs._info(self._join(path), **kwargs) - info = info.copy() - info["name"] = self._relpath(info["name"]) - return info - - def info(self, path, **kwargs): - info = self.fs.info(self._join(path), **kwargs) - info = info.copy() - info["name"] = self._relpath(info["name"]) - return info - - async def _ls(self, path, detail=True, **kwargs): - ret = (await self.fs._ls(self._join(path), detail=detail, **kwargs)).copy() - if detail: - out = [] - for entry in ret: - entry = entry.copy() - entry["name"] = self._relpath(entry["name"]) - out.append(entry) - return out - - return self._relpath(ret) - - def ls(self, path, detail=True, **kwargs): - ret = self.fs.ls(self._join(path), detail=detail, **kwargs).copy() - if detail: - out = [] - for entry in ret: - entry = entry.copy() - entry["name"] = self._relpath(entry["name"]) - out.append(entry) - return out - - return self._relpath(ret) - - async def _walk(self, path, *args, **kwargs): - async for root, dirs, files in self.fs._walk(self._join(path), *args, **kwargs): - yield self._relpath(root), dirs, files - - def walk(self, path, *args, **kwargs): - for root, dirs, files in self.fs.walk(self._join(path), *args, **kwargs): - yield self._relpath(root), dirs, files - - async def _glob(self, path, **kwargs): - detail = kwargs.get("detail", False) - ret = await self.fs._glob(self._join(path), **kwargs) - if detail: - return {self._relpath(path): info for path, info in ret.items()} - return self._relpath(ret) - - def glob(self, path, **kwargs): - detail = kwargs.get("detail", False) - ret = self.fs.glob(self._join(path), **kwargs) - if detail: - return {self._relpath(path): info for path, info in ret.items()} - return self._relpath(ret) - - async def _du(self, path, *args, **kwargs): - total = kwargs.get("total", True) - ret = await self.fs._du(self._join(path), *args, **kwargs) - if total: - return ret - - return {self._relpath(path): size for path, size in ret.items()} - - def du(self, path, *args, **kwargs): - total = kwargs.get("total", True) - ret = self.fs.du(self._join(path), *args, **kwargs) - if total: - return ret - - return {self._relpath(path): size for path, size in ret.items()} - - async def _find(self, path, *args, **kwargs): - detail = kwargs.get("detail", False) - ret = await self.fs._find(self._join(path), *args, **kwargs) - if detail: - return {self._relpath(path): info for path, info in ret.items()} - return self._relpath(ret) - - def find(self, path, *args, **kwargs): - detail = kwargs.get("detail", False) - ret = self.fs.find(self._join(path), *args, **kwargs) - if detail: - return {self._relpath(path): info for path, info in ret.items()} - return self._relpath(ret) - - async def _expand_path(self, path, *args, **kwargs): - return self._relpath( - await self.fs._expand_path(self._join(path), *args, **kwargs) - ) - - def expand_path(self, path, *args, **kwargs): - return self._relpath(self.fs.expand_path(self._join(path), *args, **kwargs)) - - async def _mkdir(self, path, *args, **kwargs): - return await self.fs._mkdir(self._join(path), *args, **kwargs) - - def mkdir(self, path, *args, **kwargs): - return self.fs.mkdir(self._join(path), *args, **kwargs) - - async def _makedirs(self, path, *args, **kwargs): - return await self.fs._makedirs(self._join(path), *args, **kwargs) - - def makedirs(self, path, *args, **kwargs): - return self.fs.makedirs(self._join(path), *args, **kwargs) - - def rmdir(self, path): - return self.fs.rmdir(self._join(path)) - - def mv(self, path1, path2, **kwargs): - return self.fs.mv( - self._join(path1), - self._join(path2), - **kwargs, - ) - - def touch(self, path, **kwargs): - return self.fs.touch(self._join(path), **kwargs) - - def created(self, path): - return self.fs.created(self._join(path)) - - def modified(self, path): - return self.fs.modified(self._join(path)) - - def sign(self, path, *args, **kwargs): - return self.fs.sign(self._join(path), *args, **kwargs) - - def __repr__(self): - return f"{self.__class__.__qualname__}(path='{self.path}', fs={self.fs})" - - def open( - self, - path, - *args, - **kwargs, - ): - return self.fs.open( - self._join(path), - *args, - **kwargs, - ) - - async def open_async( - self, - path, - *args, - **kwargs, - ): - return await self.fs.open_async( - self._join(path), - *args, - **kwargs, - ) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/ftp.py b/venv/lib/python3.10/site-packages/fsspec/implementations/ftp.py deleted file mode 100644 index ca151c6ea3cc2bb514701cd95fd5258bed3c9899..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/ftp.py +++ /dev/null @@ -1,437 +0,0 @@ -import os -import ssl -import uuid -from ftplib import FTP, FTP_TLS, Error, error_perm -from typing import Any - -from ..spec import AbstractBufferedFile, AbstractFileSystem -from ..utils import infer_storage_options, isfilelike - -SECURITY_PROTOCOL_MAP = { - "tls": ssl.PROTOCOL_TLS, - "tlsv1": ssl.PROTOCOL_TLSv1, - "tlsv1_1": ssl.PROTOCOL_TLSv1_1, - "tlsv1_2": ssl.PROTOCOL_TLSv1_2, - "sslv23": ssl.PROTOCOL_SSLv23, -} - - -class ImplicitFTPTLS(FTP_TLS): - """ - FTP_TLS subclass that automatically wraps sockets in SSL - to support implicit FTPS. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._sock = None - - @property - def sock(self): - """Return the socket.""" - return self._sock - - @sock.setter - def sock(self, value): - """When modifying the socket, ensure that it is ssl wrapped.""" - if value is not None and not isinstance(value, ssl.SSLSocket): - value = self.context.wrap_socket(value) - self._sock = value - - -class FTPFileSystem(AbstractFileSystem): - """A filesystem over classic FTP""" - - root_marker = "/" - cachable = False - protocol = "ftp" - - def __init__( - self, - host, - port=21, - username=None, - password=None, - acct=None, - block_size=None, - tempdir=None, - timeout=30, - encoding="utf-8", - tls=False, - **kwargs, - ): - """ - You can use _get_kwargs_from_urls to get some kwargs from - a reasonable FTP url. - - Authentication will be anonymous if username/password are not - given. - - Parameters - ---------- - host: str - The remote server name/ip to connect to - port: int - Port to connect with - username: str or None - If authenticating, the user's identifier - password: str of None - User's password on the server, if using - acct: str or None - Some servers also need an "account" string for auth - block_size: int or None - If given, the read-ahead or write buffer size. - tempdir: str - Directory on remote to put temporary files when in a transaction - timeout: int - Timeout of the ftp connection in seconds - encoding: str - Encoding to use for directories and filenames in FTP connection - tls: bool or str - Enable FTP-TLS for secure connections: - - False: Plain FTP (default) - - True: Explicit TLS (FTPS with AUTH TLS command) - - "tls": Auto-negotiate highest protocol - - "tlsv1": TLS v1.0 - - "tlsv1_1": TLS v1.1 - - "tlsv1_2": TLS v1.2 - """ - super().__init__(**kwargs) - self.host = host - self.port = port - self.tempdir = tempdir or "/tmp" - self.cred = username or "", password or "", acct or "" - self.timeout = timeout - self.encoding = encoding - if block_size is not None: - self.blocksize = block_size - else: - self.blocksize = 2**16 - self.tls = tls - self._connect() - if isinstance(self.tls, bool) and self.tls: - self.ftp.prot_p() - - def _connect(self): - security = None - if self.tls: - if isinstance(self.tls, str): - ftp_cls = ImplicitFTPTLS - security = SECURITY_PROTOCOL_MAP.get( - self.tls, - f"Not supported {self.tls} protocol", - ) - if isinstance(security, str): - raise ValueError(security) - else: - ftp_cls = FTP_TLS - else: - ftp_cls = FTP - self.ftp = ftp_cls(timeout=self.timeout, encoding=self.encoding) - if security: - self.ftp.ssl_version = security - self.ftp.connect(self.host, self.port) - self.ftp.login(*self.cred) - - @classmethod - def _strip_protocol(cls, path): - return "/" + infer_storage_options(path)["path"].lstrip("/").rstrip("/") - - @staticmethod - def _get_kwargs_from_urls(urlpath): - out = infer_storage_options(urlpath) - out.pop("path", None) - out.pop("protocol", None) - return out - - def ls(self, path, detail=True, **kwargs): - path = self._strip_protocol(path) - out = [] - if path not in self.dircache: - try: - try: - out = [ - (fn, details) - for (fn, details) in self.ftp.mlsd(path) - if fn not in [".", ".."] - and details["type"] not in ["pdir", "cdir"] - ] - except error_perm: - out = _mlsd2(self.ftp, path) # Not platform independent - for fn, details in out: - details["name"] = "/".join( - ["" if path == "/" else path, fn.lstrip("/")] - ) - if details["type"] == "file": - details["size"] = int(details["size"]) - else: - details["size"] = 0 - if details["type"] == "dir": - details["type"] = "directory" - self.dircache[path] = out - except Error: - try: - info = self.info(path) - if info["type"] == "file": - out = [(path, info)] - except (Error, IndexError) as exc: - raise FileNotFoundError(path) from exc - files = self.dircache.get(path, out) - if not detail: - return sorted([fn for fn, details in files]) - return [details for fn, details in files] - - def info(self, path, **kwargs): - # implement with direct method - path = self._strip_protocol(path) - if path == "/": - # special case, since this dir has no real entry - return {"name": "/", "size": 0, "type": "directory"} - files = self.ls(self._parent(path).lstrip("/"), True) - try: - out = next(f for f in files if f["name"] == path) - except StopIteration as exc: - raise FileNotFoundError(path) from exc - return out - - def get_file(self, rpath, lpath, **kwargs): - if self.isdir(rpath): - if not os.path.exists(lpath): - os.mkdir(lpath) - return - if isfilelike(lpath): - outfile = lpath - else: - outfile = open(lpath, "wb") - - def cb(x): - outfile.write(x) - - self.ftp.retrbinary( - f"RETR {rpath}", - blocksize=self.blocksize, - callback=cb, - ) - if not isfilelike(lpath): - outfile.close() - - def cat_file(self, path, start=None, end=None, **kwargs): - if end is not None: - return super().cat_file(path, start, end, **kwargs) - out = [] - - def cb(x): - out.append(x) - - try: - self.ftp.retrbinary( - f"RETR {path}", - blocksize=self.blocksize, - rest=start, - callback=cb, - ) - except (Error, error_perm) as orig_exc: - raise FileNotFoundError(path) from orig_exc - return b"".join(out) - - def _open( - self, - path, - mode="rb", - block_size=None, - cache_options=None, - autocommit=True, - **kwargs, - ): - path = self._strip_protocol(path) - block_size = block_size or self.blocksize - return FTPFile( - self, - path, - mode=mode, - block_size=block_size, - tempdir=self.tempdir, - autocommit=autocommit, - cache_options=cache_options, - ) - - def _rm(self, path): - path = self._strip_protocol(path) - self.ftp.delete(path) - self.invalidate_cache(self._parent(path)) - - def rm(self, path, recursive=False, maxdepth=None): - paths = self.expand_path(path, recursive=recursive, maxdepth=maxdepth) - for p in reversed(paths): - if self.isfile(p): - self.rm_file(p) - else: - self.rmdir(p) - - def mkdir(self, path: str, create_parents: bool = True, **kwargs: Any) -> None: - path = self._strip_protocol(path) - parent = self._parent(path) - if parent != self.root_marker and not self.exists(parent) and create_parents: - self.mkdir(parent, create_parents=create_parents) - - self.ftp.mkd(path) - self.invalidate_cache(self._parent(path)) - - def makedirs(self, path: str, exist_ok: bool = False) -> None: - path = self._strip_protocol(path) - if self.exists(path): - # NB: "/" does not "exist" as it has no directory entry - if not exist_ok: - raise FileExistsError(f"{path} exists without `exist_ok`") - # exists_ok=True -> no-op - else: - self.mkdir(path, create_parents=True) - - def rmdir(self, path): - path = self._strip_protocol(path) - self.ftp.rmd(path) - self.invalidate_cache(self._parent(path)) - - def mv(self, path1, path2, **kwargs): - path1 = self._strip_protocol(path1) - path2 = self._strip_protocol(path2) - self.ftp.rename(path1, path2) - self.invalidate_cache(self._parent(path1)) - self.invalidate_cache(self._parent(path2)) - - def __del__(self): - self.ftp.close() - - def invalidate_cache(self, path=None): - if path is None: - self.dircache.clear() - else: - self.dircache.pop(path, None) - super().invalidate_cache(path) - - -class TransferDone(Exception): - """Internal exception to break out of transfer""" - - pass - - -class FTPFile(AbstractBufferedFile): - """Interact with a remote FTP file with read/write buffering""" - - def __init__( - self, - fs, - path, - mode="rb", - block_size="default", - autocommit=True, - cache_type="readahead", - cache_options=None, - **kwargs, - ): - super().__init__( - fs, - path, - mode=mode, - block_size=block_size, - autocommit=autocommit, - cache_type=cache_type, - cache_options=cache_options, - **kwargs, - ) - if not autocommit: - self.target = self.path - self.path = "/".join([kwargs["tempdir"], str(uuid.uuid4())]) - - def commit(self): - self.fs.mv(self.path, self.target) - - def discard(self): - self.fs.rm(self.path) - - def _fetch_range(self, start, end): - """Get bytes between given byte limits - - Implemented by raising an exception in the fetch callback when the - number of bytes received reaches the requested amount. - - Will fail if the server does not respect the REST command on - retrieve requests. - """ - out = [] - total = [0] - - def callback(x): - total[0] += len(x) - if total[0] > end - start: - out.append(x[: (end - start) - total[0]]) - if end < self.size: - raise TransferDone - else: - out.append(x) - - if total[0] == end - start and end < self.size: - raise TransferDone - - try: - self.fs.ftp.retrbinary( - f"RETR {self.path}", - blocksize=self.blocksize, - rest=start, - callback=callback, - ) - except TransferDone: - try: - # stop transfer, we got enough bytes for this block - self.fs.ftp.abort() - self.fs.ftp.getmultiline() - except Error: - self.fs._connect() - - return b"".join(out) - - def _upload_chunk(self, final=False): - self.buffer.seek(0) - self.fs.ftp.storbinary( - f"STOR {self.path}", self.buffer, blocksize=self.blocksize, rest=self.offset - ) - return True - - -def _mlsd2(ftp, path="."): - """ - Fall back to using `dir` instead of `mlsd` if not supported. - - This parses a Linux style `ls -l` response to `dir`, but the response may - be platform dependent. - - Parameters - ---------- - ftp: ftplib.FTP - path: str - Expects to be given path, but defaults to ".". - """ - lines = [] - minfo = [] - ftp.dir(path, lines.append) - for line in lines: - split_line = line.split() - if len(split_line) < 9: - continue - this = ( - split_line[-1], - { - "modify": " ".join(split_line[5:8]), - "unix.owner": split_line[2], - "unix.group": split_line[3], - "unix.mode": split_line[0], - "size": split_line[4], - }, - ) - if this[1]["unix.mode"][0] == "d": - this[1]["type"] = "dir" - else: - this[1]["type"] = "file" - minfo.append(this) - return minfo diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/gist.py b/venv/lib/python3.10/site-packages/fsspec/implementations/gist.py deleted file mode 100644 index ad9ac0b6a1cdbcfba6188e2cdeab2350bb9aad0a..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/gist.py +++ /dev/null @@ -1,241 +0,0 @@ -import requests - -from ..spec import AbstractFileSystem -from ..utils import infer_storage_options -from .memory import MemoryFile - - -class GistFileSystem(AbstractFileSystem): - """ - Interface to files in a single GitHub Gist. - - Provides read-only access to a gist's files. Gists do not contain - subdirectories, so file listing is straightforward. - - Parameters - ---------- - gist_id: str - The ID of the gist you want to access (the long hex value from the URL). - filenames: list[str] (optional) - If provided, only make a file system representing these files, and do not fetch - the list of all files for this gist. - sha: str (optional) - If provided, fetch a particular revision of the gist. If omitted, - the latest revision is used. - username: str (optional) - GitHub username for authentication. - token: str (optional) - GitHub personal access token (required if username is given), or. - timeout: (float, float) or float, optional - Connect and read timeouts for requests (default 60s each). - kwargs: dict - Stored on `self.request_kw` and passed to `requests.get` when fetching Gist - metadata or reading ("opening") a file. - """ - - protocol = "gist" - gist_url = "https://api.github.com/gists/{gist_id}" - gist_rev_url = "https://api.github.com/gists/{gist_id}/{sha}" - - def __init__( - self, - gist_id, - filenames=None, - sha=None, - username=None, - token=None, - timeout=None, - **kwargs, - ): - super().__init__() - self.gist_id = gist_id - self.filenames = filenames - self.sha = sha # revision of the gist (optional) - if username is not None and token is None: - raise ValueError("User auth requires a token") - self.username = username - self.token = token - self.request_kw = kwargs - # Default timeouts to 60s connect/read if none provided - self.timeout = timeout if timeout is not None else (60, 60) - - # We use a single-level "directory" cache, because a gist is essentially flat - self.dircache[""] = self._fetch_file_list() - - @property - def kw(self): - """Auth parameters passed to 'requests' if we have username/token.""" - kw = { - "headers": { - "Accept": "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - } - } - kw.update(self.request_kw) - if self.username and self.token: - kw["auth"] = (self.username, self.token) - elif self.token: - kw["headers"]["Authorization"] = f"Bearer {self.token}" - return kw - - def _fetch_gist_metadata(self): - """ - Fetch the JSON metadata for this gist (possibly for a specific revision). - """ - if self.sha: - url = self.gist_rev_url.format(gist_id=self.gist_id, sha=self.sha) - else: - url = self.gist_url.format(gist_id=self.gist_id) - - r = requests.get(url, timeout=self.timeout, **self.kw) - if r.status_code == 404: - raise FileNotFoundError( - f"Gist not found: {self.gist_id}@{self.sha or 'latest'}" - ) - r.raise_for_status() - return r.json() - - def _fetch_file_list(self): - """ - Returns a list of dicts describing each file in the gist. These get stored - in self.dircache[""]. - """ - meta = self._fetch_gist_metadata() - if self.filenames: - available_files = meta.get("files", {}) - files = {} - for fn in self.filenames: - if fn not in available_files: - raise FileNotFoundError(fn) - files[fn] = available_files[fn] - else: - files = meta.get("files", {}) - - out = [] - for fname, finfo in files.items(): - if finfo is None: - # Occasionally GitHub returns a file entry with null if it was deleted - continue - # Build a directory entry - out.append( - { - "name": fname, # file's name - "type": "file", # gists have no subdirectories - "size": finfo.get("size", 0), # file size in bytes - "raw_url": finfo.get("raw_url"), - } - ) - return out - - @classmethod - def _strip_protocol(cls, path): - """ - Remove 'gist://' from the path, if present. - """ - # The default infer_storage_options can handle gist://username:token@id/file - # or gist://id/file, but let's ensure we handle a normal usage too. - # We'll just strip the protocol prefix if it exists. - path = infer_storage_options(path).get("path", path) - return path.lstrip("/") - - @staticmethod - def _get_kwargs_from_urls(path): - """ - Parse 'gist://' style URLs into GistFileSystem constructor kwargs. - For example: - gist://:TOKEN@/file.txt - gist://username:TOKEN@/file.txt - """ - so = infer_storage_options(path) - out = {} - if "username" in so and so["username"]: - out["username"] = so["username"] - if "password" in so and so["password"]: - out["token"] = so["password"] - if "host" in so and so["host"]: - # We interpret 'host' as the gist ID - out["gist_id"] = so["host"] - - # Extract SHA and filename from path - if "path" in so and so["path"]: - path_parts = so["path"].rsplit("/", 2)[-2:] - if len(path_parts) == 2: - if path_parts[0]: # SHA present - out["sha"] = path_parts[0] - if path_parts[1]: # filename also present - out["filenames"] = [path_parts[1]] - - return out - - def ls(self, path="", detail=False, **kwargs): - """ - List files in the gist. Gists are single-level, so any 'path' is basically - the filename, or empty for all files. - - Parameters - ---------- - path : str, optional - The filename to list. If empty, returns all files in the gist. - detail : bool, default False - If True, return a list of dicts; if False, return a list of filenames. - """ - path = self._strip_protocol(path or "") - # If path is empty, return all - if path == "": - results = self.dircache[""] - else: - # We want just the single file with this name - all_files = self.dircache[""] - results = [f for f in all_files if f["name"] == path] - if not results: - raise FileNotFoundError(path) - if detail: - return results - else: - return sorted(f["name"] for f in results) - - def _open(self, path, mode="rb", block_size=None, **kwargs): - """ - Read a single file from the gist. - """ - if mode != "rb": - raise NotImplementedError("GitHub Gist FS is read-only (no write).") - - path = self._strip_protocol(path) - # Find the file entry in our dircache - matches = [f for f in self.dircache[""] if f["name"] == path] - if not matches: - raise FileNotFoundError(path) - finfo = matches[0] - - raw_url = finfo.get("raw_url") - if not raw_url: - raise FileNotFoundError(f"No raw_url for file: {path}") - - r = requests.get(raw_url, timeout=self.timeout, **self.kw) - if r.status_code == 404: - raise FileNotFoundError(path) - r.raise_for_status() - return MemoryFile(path, None, r.content) - - def cat(self, path, recursive=False, on_error="raise", **kwargs): - """ - Return {path: contents} for the given file or files. If 'recursive' is True, - and path is empty, returns all files in the gist. - """ - paths = self.expand_path(path, recursive=recursive) - out = {} - for p in paths: - try: - with self.open(p, "rb") as f: - out[p] = f.read() - except FileNotFoundError as e: - if on_error == "raise": - raise e - elif on_error == "omit": - pass # skip - else: - out[p] = e - if len(paths) == 1 and paths[0] == path: - return out[path] - return out diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/git.py b/venv/lib/python3.10/site-packages/fsspec/implementations/git.py deleted file mode 100644 index 808d293a1c991ea87d19a2129f3e56d9b813daaa..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/git.py +++ /dev/null @@ -1,114 +0,0 @@ -import os - -import pygit2 - -from fsspec.spec import AbstractFileSystem - -from .memory import MemoryFile - - -class GitFileSystem(AbstractFileSystem): - """Browse the files of a local git repo at any hash/tag/branch - - (experimental backend) - """ - - root_marker = "" - cachable = True - - def __init__(self, path=None, fo=None, ref=None, **kwargs): - """ - - Parameters - ---------- - path: str (optional) - Local location of the repo (uses current directory if not given). - May be deprecated in favour of ``fo``. When used with a higher - level function such as fsspec.open(), may be of the form - "git://[path-to-repo[:]][ref@]path/to/file" (but the actual - file path should not contain "@" or ":"). - fo: str (optional) - Same as ``path``, but passed as part of a chained URL. This one - takes precedence if both are given. - ref: str (optional) - Reference to work with, could be a hash, tag or branch name. Defaults - to current working tree. Note that ``ls`` and ``open`` also take hash, - so this becomes the default for those operations - kwargs - """ - super().__init__(**kwargs) - self.repo = pygit2.Repository(fo or path or os.getcwd()) - self.ref = ref or "master" - - @classmethod - def _strip_protocol(cls, path): - path = super()._strip_protocol(path).lstrip("/") - if ":" in path: - path = path.split(":", 1)[1] - if "@" in path: - path = path.split("@", 1)[1] - return path.lstrip("/") - - def _path_to_object(self, path, ref): - comm, ref = self.repo.resolve_refish(ref or self.ref) - parts = path.split("/") - tree = comm.tree - for part in parts: - if part and isinstance(tree, pygit2.Tree): - if part not in tree: - raise FileNotFoundError(path) - tree = tree[part] - return tree - - @staticmethod - def _get_kwargs_from_urls(path): - path = path.removeprefix("git://") - out = {} - if ":" in path: - out["path"], path = path.split(":", 1) - if "@" in path: - out["ref"], path = path.split("@", 1) - return out - - @staticmethod - def _object_to_info(obj, path=None): - # obj.name and obj.filemode are None for the root tree! - is_dir = isinstance(obj, pygit2.Tree) - return { - "type": "directory" if is_dir else "file", - "name": ( - "/".join([path, obj.name or ""]).lstrip("/") if path else obj.name - ), - "hex": str(obj.id), - "mode": "100644" if obj.filemode is None else f"{obj.filemode:o}", - "size": 0 if is_dir else obj.size, - } - - def ls(self, path, detail=True, ref=None, **kwargs): - tree = self._path_to_object(self._strip_protocol(path), ref) - return [ - GitFileSystem._object_to_info(obj, path) - if detail - else GitFileSystem._object_to_info(obj, path)["name"] - for obj in (tree if isinstance(tree, pygit2.Tree) else [tree]) - ] - - def info(self, path, ref=None, **kwargs): - tree = self._path_to_object(self._strip_protocol(path), ref) - return GitFileSystem._object_to_info(tree, path) - - def ukey(self, path, ref=None): - return self.info(path, ref=ref)["hex"] - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - ref=None, - **kwargs, - ): - obj = self._path_to_object(path, ref or self.ref) - return MemoryFile(data=obj.data) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/github.py b/venv/lib/python3.10/site-packages/fsspec/implementations/github.py deleted file mode 100644 index 3630f6db54413e2c396f6cc1b6b10cd379200043..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/github.py +++ /dev/null @@ -1,333 +0,0 @@ -import base64 -import re - -import requests - -from ..spec import AbstractFileSystem -from ..utils import infer_storage_options -from .memory import MemoryFile - - -class GithubFileSystem(AbstractFileSystem): - """Interface to files in github - - An instance of this class provides the files residing within a remote github - repository. You may specify a point in the repos history, by SHA, branch - or tag (default is current master). - - For files less than 1 MB in size, file content is returned directly in a - MemoryFile. For larger files, or for files tracked by git-lfs, file content - is returned as an HTTPFile wrapping the ``download_url`` provided by the - GitHub API. - - When using fsspec.open, allows URIs of the form: - - - "github://path/file", in which case you must specify org, repo and - may specify sha in the extra args - - 'github://org:repo@/precip/catalog.yml', where the org and repo are - part of the URI - - 'github://org:repo@sha/precip/catalog.yml', where the sha is also included - - ``sha`` can be the full or abbreviated hex of the commit you want to fetch - from, or a branch or tag name (so long as it doesn't contain special characters - like "/", "?", which would have to be HTTP-encoded). - - For authorised access, you must provide username and token, which can be made - at https://github.com/settings/tokens - """ - - url = "https://api.github.com/repos/{org}/{repo}/git/trees/{sha}" - content_url = "https://api.github.com/repos/{org}/{repo}/contents/{path}?ref={sha}" - protocol = "github" - timeout = (60, 60) # connect, read timeouts - - def __init__( - self, org, repo, sha=None, username=None, token=None, timeout=None, **kwargs - ): - super().__init__(**kwargs) - self.org = org - self.repo = repo - if (username is None) ^ (token is None): - raise ValueError("Auth required both username and token") - self.username = username - self.token = token - if timeout is not None: - self.timeout = timeout - if sha is None: - # look up default branch (not necessarily "master") - u = "https://api.github.com/repos/{org}/{repo}" - r = requests.get( - u.format(org=org, repo=repo), timeout=self.timeout, **self.kw - ) - r.raise_for_status() - sha = r.json()["default_branch"] - - self.root = sha - self.ls("") - try: - from .http import HTTPFileSystem - - self.http_fs = HTTPFileSystem(**kwargs) - except ImportError: - self.http_fs = None - - @property - def kw(self): - if self.username: - return {"auth": (self.username, self.token)} - return {} - - @classmethod - def repos(cls, org_or_user, is_org=True): - """List repo names for given org or user - - This may become the top level of the FS - - Parameters - ---------- - org_or_user: str - Name of the github org or user to query - is_org: bool (default True) - Whether the name is an organisation (True) or user (False) - - Returns - ------- - List of string - """ - r = requests.get( - f"https://api.github.com/{['users', 'orgs'][is_org]}/{org_or_user}/repos", - timeout=cls.timeout, - ) - r.raise_for_status() - return [repo["name"] for repo in r.json()] - - @property - def tags(self): - """Names of tags in the repo""" - r = requests.get( - f"https://api.github.com/repos/{self.org}/{self.repo}/tags", - timeout=self.timeout, - **self.kw, - ) - r.raise_for_status() - return [t["name"] for t in r.json()] - - @property - def branches(self): - """Names of branches in the repo""" - r = requests.get( - f"https://api.github.com/repos/{self.org}/{self.repo}/branches", - timeout=self.timeout, - **self.kw, - ) - r.raise_for_status() - return [t["name"] for t in r.json()] - - @property - def refs(self): - """Named references, tags and branches""" - return {"tags": self.tags, "branches": self.branches} - - def ls(self, path, detail=False, sha=None, _sha=None, **kwargs): - """List files at given path - - Parameters - ---------- - path: str - Location to list, relative to repo root - detail: bool - If True, returns list of dicts, one per file; if False, returns - list of full filenames only - sha: str (optional) - List at the given point in the repo history, branch or tag name or commit - SHA - _sha: str (optional) - List this specific tree object (used internally to descend into trees) - """ - path = self._strip_protocol(path) - if path == "": - _sha = sha or self.root - if _sha is None: - parts = path.rstrip("/").split("/") - so_far = "" - _sha = sha or self.root - for part in parts: - out = self.ls(so_far, True, sha=sha, _sha=_sha) - so_far += "/" + part if so_far else part - out = [o for o in out if o["name"] == so_far] - if not out: - raise FileNotFoundError(path) - out = out[0] - if out["type"] == "file": - if detail: - return [out] - else: - return path - _sha = out["sha"] - if path not in self.dircache or sha not in [self.root, None]: - r = requests.get( - self.url.format(org=self.org, repo=self.repo, sha=_sha), - timeout=self.timeout, - **self.kw, - ) - if r.status_code == 404: - raise FileNotFoundError(path) - r.raise_for_status() - types = {"blob": "file", "tree": "directory"} - out = [ - { - "name": path + "/" + f["path"] if path else f["path"], - "mode": f["mode"], - "type": types[f["type"]], - "size": f.get("size", 0), - "sha": f["sha"], - } - for f in r.json()["tree"] - if f["type"] in types - ] - if sha in [self.root, None]: - self.dircache[path] = out - else: - out = self.dircache[path] - if detail: - return out - else: - return sorted([f["name"] for f in out]) - - def invalidate_cache(self, path=None): - self.dircache.clear() - - @classmethod - def _strip_protocol(cls, path): - opts = infer_storage_options(path) - if "username" not in opts: - return super()._strip_protocol(path) - return opts["path"].lstrip("/") - - @staticmethod - def _get_kwargs_from_urls(path): - opts = infer_storage_options(path) - if "username" not in opts: - return {} - out = {"org": opts["username"], "repo": opts["password"]} - if opts["host"]: - out["sha"] = opts["host"] - return out - - def _open( - self, - path, - mode="rb", - block_size=None, - cache_options=None, - sha=None, - **kwargs, - ): - if mode != "rb": - raise NotImplementedError - - # construct a url to hit the GitHub API's repo contents API - url = self.content_url.format( - org=self.org, repo=self.repo, path=path, sha=sha or self.root - ) - - # make a request to this API, and parse the response as JSON - r = requests.get(url, timeout=self.timeout, **self.kw) - if r.status_code == 404: - raise FileNotFoundError(path) - r.raise_for_status() - content_json = r.json() - - # if the response's content key is not empty, try to parse it as base64 - if content_json["content"]: - content = base64.b64decode(content_json["content"]) - - # as long as the content does not start with the string - # "version https://git-lfs.github.com/" - # then it is probably not a git-lfs pointer and we can just return - # the content directly - if not content.startswith(b"version https://git-lfs.github.com/"): - return MemoryFile(None, None, content) - - # we land here if the content was not present in the first response - # (regular file over 1MB or git-lfs tracked file) - # in this case, we get let the HTTPFileSystem handle the download - if self.http_fs is None: - raise ImportError( - "Please install fsspec[http] to access github files >1 MB " - "or git-lfs tracked files." - ) - return self.http_fs.open( - content_json["download_url"], - mode=mode, - block_size=block_size, - cache_options=cache_options, - **kwargs, - ) - - def rm(self, path, recursive=False, maxdepth=None, message=None): - path = self.expand_path(path, recursive=recursive, maxdepth=maxdepth) - for p in reversed(path): - self.rm_file(p, message=message) - - def rm_file(self, path, message=None, **kwargs): - """ - Remove a file from a specified branch using a given commit message. - - Since Github DELETE operation requires a branch name, and we can't reliably - determine whether the provided SHA refers to a branch, tag, or commit, we - assume it's a branch. If it's not, the user will encounter an error when - attempting to retrieve the file SHA or delete the file. - - Parameters - ---------- - path: str - The file's location relative to the repository root. - message: str, optional - The commit message for the deletion. - """ - - if not self.username: - raise ValueError("Authentication required") - - path = self._strip_protocol(path) - - # Attempt to get SHA from cache or Github API - sha = self._get_sha_from_cache(path) - if not sha: - url = self.content_url.format( - org=self.org, repo=self.repo, path=path.lstrip("/"), sha=self.root - ) - r = requests.get(url, timeout=self.timeout, **self.kw) - if r.status_code == 404: - raise FileNotFoundError(path) - r.raise_for_status() - sha = r.json()["sha"] - - # Delete the file - delete_url = self.content_url.format( - org=self.org, repo=self.repo, path=path, sha=self.root - ) - branch = self.root - data = { - "message": message or f"Delete {path}", - "sha": sha, - **({"branch": branch} if branch else {}), - } - - r = requests.delete(delete_url, json=data, timeout=self.timeout, **self.kw) - error_message = r.json().get("message", "") - if re.search(r"Branch .+ not found", error_message): - error = "Remove only works when the filesystem is initialised from a branch or default (None)" - raise ValueError(error) - r.raise_for_status() - - self.invalidate_cache(path) - - def _get_sha_from_cache(self, path): - for entries in self.dircache.values(): - for entry in entries: - entry_path = entry.get("name") - if entry_path and entry_path == path and "sha" in entry: - return entry["sha"] - return None diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/http.py b/venv/lib/python3.10/site-packages/fsspec/implementations/http.py deleted file mode 100644 index dfb1bc36074ff4c85463133387601ae16ae1280e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/http.py +++ /dev/null @@ -1,897 +0,0 @@ -import asyncio -import io -import logging -import re -import weakref -from copy import copy -from urllib.parse import urlparse - -import aiohttp -import yarl - -from fsspec.asyn import AbstractAsyncStreamedFile, AsyncFileSystem, sync, sync_wrapper -from fsspec.callbacks import DEFAULT_CALLBACK -from fsspec.exceptions import FSTimeoutError -from fsspec.spec import AbstractBufferedFile -from fsspec.utils import ( - DEFAULT_BLOCK_SIZE, - glob_translate, - isfilelike, - nullcontext, - tokenize, -) - -from ..caching import AllBytes - -# https://stackoverflow.com/a/15926317/3821154 -ex = re.compile(r"""<(a|A)\s+(?:[^>]*?\s+)?(href|HREF)=["'](?P[^"']+)""") -ex2 = re.compile(r"""(?Phttp[s]?://[-a-zA-Z0-9@:%_+.~#?&/=]+)""") -logger = logging.getLogger("fsspec.http") - - -async def get_client(**kwargs): - return aiohttp.ClientSession(**kwargs) - - -class HTTPFileSystem(AsyncFileSystem): - """ - Simple File-System for fetching data via HTTP(S) - - ``ls()`` is implemented by loading the parent page and doing a regex - match on the result. If simple_link=True, anything of the form - "http(s)://server.com/stuff?thing=other"; otherwise only links within - HTML href tags will be used. - """ - - protocol = ("http", "https") - sep = "/" - - def __init__( - self, - simple_links=True, - block_size=None, - same_scheme=True, - size_policy=None, - cache_type="bytes", - cache_options=None, - asynchronous=False, - loop=None, - client_kwargs=None, - get_client=get_client, - encoded=False, - **storage_options, - ): - """ - NB: if this is called async, you must await set_client - - Parameters - ---------- - block_size: int - Blocks to read bytes; if 0, will default to raw requests file-like - objects instead of HTTPFile instances - simple_links: bool - If True, will consider both HTML tags and anything that looks - like a URL; if False, will consider only the former. - same_scheme: True - When doing ls/glob, if this is True, only consider paths that have - http/https matching the input URLs. - size_policy: this argument is deprecated - client_kwargs: dict - Passed to aiohttp.ClientSession, see - https://docs.aiohttp.org/en/stable/client_reference.html - For example, ``{'auth': aiohttp.BasicAuth('user', 'pass')}`` - get_client: Callable[..., aiohttp.ClientSession] - A callable, which takes keyword arguments and constructs - an aiohttp.ClientSession. Its state will be managed by - the HTTPFileSystem class. - storage_options: key-value - Any other parameters passed on to requests - cache_type, cache_options: defaults used in open() - """ - super().__init__(self, asynchronous=asynchronous, loop=loop, **storage_options) - self.block_size = block_size if block_size is not None else DEFAULT_BLOCK_SIZE - self.simple_links = simple_links - self.same_schema = same_scheme - self.cache_type = cache_type - self.cache_options = cache_options - self.client_kwargs = client_kwargs or {} - self.get_client = get_client - self.encoded = encoded - self.kwargs = storage_options - self._session = None - - # Clean caching-related parameters from `storage_options` - # before propagating them as `request_options` through `self.kwargs`. - # TODO: Maybe rename `self.kwargs` to `self.request_options` to make - # it clearer. - request_options = copy(storage_options) - self.use_listings_cache = request_options.pop("use_listings_cache", False) - request_options.pop("listings_expiry_time", None) - request_options.pop("max_paths", None) - request_options.pop("skip_instance_cache", None) - self.kwargs = request_options - - @property - def fsid(self): - return "http" - - def encode_url(self, url): - return yarl.URL(url, encoded=self.encoded) - - @staticmethod - def close_session(loop, session): - if loop is not None and loop.is_running(): - try: - sync(loop, session.close, timeout=0.1) - return - except (TimeoutError, FSTimeoutError, NotImplementedError): - pass - connector = getattr(session, "_connector", None) - if connector is not None: - # close after loop is dead - connector._close() - - async def set_session(self): - if self._session is None: - self._session = await self.get_client(loop=self.loop, **self.client_kwargs) - if not self.asynchronous: - weakref.finalize(self, self.close_session, self.loop, self._session) - return self._session - - @classmethod - def _strip_protocol(cls, path): - """For HTTP, we always want to keep the full URL""" - return path - - @classmethod - def _parent(cls, path): - # override, since _strip_protocol is different for URLs - par = super()._parent(path) - if len(par) > 7: # "http://..." - return par - return "" - - async def _ls_real(self, url, detail=True, **kwargs): - # ignoring URL-encoded arguments - kw = self.kwargs.copy() - kw.update(kwargs) - logger.debug(url) - session = await self.set_session() - async with session.get(self.encode_url(url), **self.kwargs) as r: - self._raise_not_found_for_status(r, url) - - if "Content-Type" in r.headers: - mimetype = r.headers["Content-Type"].partition(";")[0] - else: - mimetype = None - - if mimetype in ("text/html", None): - try: - text = await r.text(errors="ignore") - if self.simple_links: - links = ex2.findall(text) + [u[2] for u in ex.findall(text)] - else: - links = [u[2] for u in ex.findall(text)] - except UnicodeDecodeError: - links = [] # binary, not HTML - else: - links = [] - - out = set() - parts = urlparse(url) - for l in links: - if isinstance(l, tuple): - l = l[1] - if l.startswith("/") and len(l) > 1: - # absolute URL on this server - l = f"{parts.scheme}://{parts.netloc}{l}" - if l.startswith("http"): - if self.same_schema and l.startswith(url.rstrip("/") + "/"): - out.add(l) - elif l.replace("https", "http").startswith( - url.replace("https", "http").rstrip("/") + "/" - ): - # allowed to cross http <-> https - out.add(l) - else: - if l not in ["..", "../"]: - # Ignore FTP-like "parent" - out.add("/".join([url.rstrip("/"), l.lstrip("/")])) - if not out and url.endswith("/"): - out = await self._ls_real(url.rstrip("/"), detail=False) - if detail: - return [ - { - "name": u, - "size": None, - "type": "directory" if u.endswith("/") else "file", - } - for u in out - ] - else: - return sorted(out) - - async def _ls(self, url, detail=True, **kwargs): - if self.use_listings_cache and url in self.dircache: - out = self.dircache[url] - else: - out = await self._ls_real(url, detail=detail, **kwargs) - self.dircache[url] = out - return out - - ls = sync_wrapper(_ls) - - def _raise_not_found_for_status(self, response, url): - """ - Raises FileNotFoundError for 404s, otherwise uses raise_for_status. - """ - if response.status == 404: - raise FileNotFoundError(url) - response.raise_for_status() - - async def _cat_file(self, url, start=None, end=None, **kwargs): - kw = self.kwargs.copy() - kw.update(kwargs) - logger.debug(url) - - if start is not None or end is not None: - if start == end: - return b"" - headers = kw.pop("headers", {}).copy() - - headers["Range"] = await self._process_limits(url, start, end) - kw["headers"] = headers - session = await self.set_session() - async with session.get(self.encode_url(url), **kw) as r: - out = await r.read() - self._raise_not_found_for_status(r, url) - return out - - async def _get_file( - self, rpath, lpath, chunk_size=5 * 2**20, callback=DEFAULT_CALLBACK, **kwargs - ): - kw = self.kwargs.copy() - kw.update(kwargs) - logger.debug(rpath) - session = await self.set_session() - async with session.get(self.encode_url(rpath), **kw) as r: - try: - size = int(r.headers["content-length"]) - except (ValueError, KeyError): - size = None - - callback.set_size(size) - self._raise_not_found_for_status(r, rpath) - if isfilelike(lpath): - outfile = lpath - else: - outfile = open(lpath, "wb") # noqa: ASYNC230 - - try: - chunk = True - while chunk: - chunk = await r.content.read(chunk_size) - outfile.write(chunk) - callback.relative_update(len(chunk)) - finally: - if not isfilelike(lpath): - outfile.close() - - async def _put_file( - self, - lpath, - rpath, - chunk_size=5 * 2**20, - callback=DEFAULT_CALLBACK, - method="post", - mode="overwrite", - **kwargs, - ): - if mode != "overwrite": - raise NotImplementedError("Exclusive write") - - async def gen_chunks(): - # Support passing arbitrary file-like objects - # and use them instead of streams. - if isinstance(lpath, io.IOBase): - context = nullcontext(lpath) - use_seek = False # might not support seeking - else: - context = open(lpath, "rb") # noqa: ASYNC230 - use_seek = True - - with context as f: - if use_seek: - callback.set_size(f.seek(0, 2)) - f.seek(0) - else: - callback.set_size(getattr(f, "size", None)) - - chunk = f.read(chunk_size) - while chunk: - yield chunk - callback.relative_update(len(chunk)) - chunk = f.read(chunk_size) - - kw = self.kwargs.copy() - kw.update(kwargs) - session = await self.set_session() - - method = method.lower() - if method not in ("post", "put"): - raise ValueError( - f"method has to be either 'post' or 'put', not: {method!r}" - ) - - meth = getattr(session, method) - async with meth(self.encode_url(rpath), data=gen_chunks(), **kw) as resp: - self._raise_not_found_for_status(resp, rpath) - - async def _exists(self, path, strict=False, **kwargs): - kw = self.kwargs.copy() - kw.update(kwargs) - try: - logger.debug(path) - session = await self.set_session() - r = await session.get(self.encode_url(path), **kw) - async with r: - if strict: - self._raise_not_found_for_status(r, path) - return r.status < 400 - except FileNotFoundError: - return False - except aiohttp.ClientError: - if strict: - raise - return False - - async def _isfile(self, path, **kwargs): - return await self._exists(path, **kwargs) - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=None, # XXX: This differs from the base class. - cache_type=None, - cache_options=None, - size=None, - **kwargs, - ): - """Make a file-like object - - Parameters - ---------- - path: str - Full URL with protocol - mode: string - must be "rb" - block_size: int or None - Bytes to download in one request; use instance value if None. If - zero, will return a streaming Requests file-like instance. - kwargs: key-value - Any other parameters, passed to requests calls - """ - if mode != "rb": - raise NotImplementedError - block_size = block_size if block_size is not None else self.block_size - kw = self.kwargs.copy() - kw["asynchronous"] = self.asynchronous - kw.update(kwargs) - info = {} - size = size or info.update(self.info(path, **kwargs)) or info["size"] - session = sync(self.loop, self.set_session) - if block_size and size and info.get("partial", True): - return HTTPFile( - self, - path, - session=session, - block_size=block_size, - mode=mode, - size=size, - cache_type=cache_type or self.cache_type, - cache_options=cache_options or self.cache_options, - loop=self.loop, - **kw, - ) - else: - return HTTPStreamFile( - self, - path, - mode=mode, - loop=self.loop, - session=session, - **kw, - ) - - async def open_async(self, path, mode="rb", size=None, **kwargs): - session = await self.set_session() - if size is None: - try: - size = (await self._info(path, **kwargs))["size"] - except FileNotFoundError: - pass - return AsyncStreamFile( - self, - path, - loop=self.loop, - session=session, - size=size, - **kwargs, - ) - - def ukey(self, url): - """Unique identifier; assume HTTP files are static, unchanging""" - return tokenize(url, self.kwargs, self.protocol) - - async def _info(self, url, **kwargs): - """Get info of URL - - Tries to access location via HEAD, and then GET methods, but does - not fetch the data. - - It is possible that the server does not supply any size information, in - which case size will be given as None (and certain operations on the - corresponding file will not work). - """ - info = {} - session = await self.set_session() - - for policy in ["head", "get"]: - try: - info.update( - await _file_info( - self.encode_url(url), - size_policy=policy, - session=session, - **self.kwargs, - **kwargs, - ) - ) - if info.get("size") is not None: - break - except Exception as exc: - if policy == "get": - # If get failed, then raise a FileNotFoundError - raise FileNotFoundError(url) from exc - logger.debug("", exc_info=exc) - - return {"name": url, "size": None, **info, "type": "file"} - - async def _glob(self, path, maxdepth=None, **kwargs): - """ - Find files by glob-matching. - - This implementation is idntical to the one in AbstractFileSystem, - but "?" is not considered as a character for globbing, because it is - so common in URLs, often identifying the "query" part. - """ - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - import re - - ends_with_slash = path.endswith("/") # _strip_protocol strips trailing slash - path = self._strip_protocol(path) - append_slash_to_dirname = ends_with_slash or path.endswith(("/**", "/*")) - idx_star = path.find("*") if path.find("*") >= 0 else len(path) - idx_brace = path.find("[") if path.find("[") >= 0 else len(path) - - min_idx = min(idx_star, idx_brace) - - detail = kwargs.pop("detail", False) - - if not has_magic(path): - if await self._exists(path, **kwargs): - if not detail: - return [path] - else: - return {path: await self._info(path, **kwargs)} - else: - if not detail: - return [] # glob of non-existent returns empty - else: - return {} - elif "/" in path[:min_idx]: - min_idx = path[:min_idx].rindex("/") - root = path[: min_idx + 1] - depth = path[min_idx + 1 :].count("/") + 1 - else: - root = "" - depth = path[min_idx + 1 :].count("/") + 1 - - if "**" in path: - if maxdepth is not None: - idx_double_stars = path.find("**") - depth_double_stars = path[idx_double_stars:].count("/") + 1 - depth = depth - depth_double_stars + maxdepth - else: - depth = None - - allpaths = await self._find( - root, maxdepth=depth, withdirs=True, detail=True, **kwargs - ) - - pattern = glob_translate(path + ("/" if ends_with_slash else "")) - pattern = re.compile(pattern) - - out = { - ( - p.rstrip("/") - if not append_slash_to_dirname - and info["type"] == "directory" - and p.endswith("/") - else p - ): info - for p, info in sorted(allpaths.items()) - if pattern.match(p.rstrip("/")) - } - - if detail: - return out - else: - return list(out) - - async def _isdir(self, path): - # override, since all URLs are (also) files - try: - return bool(await self._ls(path)) - except (FileNotFoundError, ValueError): - return False - - async def _pipe_file(self, path, value, mode="overwrite", **kwargs): - """ - Write bytes to a remote file over HTTP. - - Parameters - ---------- - path : str - Target URL where the data should be written - value : bytes - Data to be written - mode : str - How to write to the file - 'overwrite' or 'append' - **kwargs : dict - Additional parameters to pass to the HTTP request - """ - url = self._strip_protocol(path) - headers = kwargs.pop("headers", {}) - headers["Content-Length"] = str(len(value)) - - session = await self.set_session() - - async with session.put(url, data=value, headers=headers, **kwargs) as r: - r.raise_for_status() - - -class HTTPFile(AbstractBufferedFile): - """ - A file-like object pointing to a remote HTTP(S) resource - - Supports only reading, with read-ahead of a predetermined block-size. - - In the case that the server does not supply the filesize, only reading of - the complete file in one go is supported. - - Parameters - ---------- - url: str - Full URL of the remote resource, including the protocol - session: aiohttp.ClientSession or None - All calls will be made within this session, to avoid restarting - connections where the server allows this - block_size: int or None - The amount of read-ahead to do, in bytes. Default is 5MB, or the value - configured for the FileSystem creating this file - size: None or int - If given, this is the size of the file in bytes, and we don't attempt - to call the server to find the value. - kwargs: all other key-values are passed to requests calls. - """ - - def __init__( - self, - fs, - url, - session=None, - block_size=None, - mode="rb", - cache_type="bytes", - cache_options=None, - size=None, - loop=None, - asynchronous=False, - **kwargs, - ): - if mode != "rb": - raise NotImplementedError("File mode not supported") - self.asynchronous = asynchronous - self.loop = loop - self.url = url - self.session = session - self.details = {"name": url, "size": size, "type": "file"} - super().__init__( - fs=fs, - path=url, - mode=mode, - block_size=block_size, - cache_type=cache_type, - cache_options=cache_options, - **kwargs, - ) - - def read(self, length=-1): - """Read bytes from file - - Parameters - ---------- - length: int - Read up to this many bytes. If negative, read all content to end of - file. If the server has not supplied the filesize, attempting to - read only part of the data will raise a ValueError. - """ - if ( - (length < 0 and self.loc == 0) # explicit read all - # but not when the size is known and fits into a block anyways - and not (self.size is not None and self.size <= self.blocksize) - ): - self._fetch_all() - if self.size is None: - if length < 0: - self._fetch_all() - else: - length = min(self.size - self.loc, length) - return super().read(length) - - async def async_fetch_all(self): - """Read whole file in one shot, without caching - - This is only called when position is still at zero, - and read() is called without a byte-count. - """ - logger.debug(f"Fetch all for {self}") - if not isinstance(self.cache, AllBytes): - r = await self.session.get(self.fs.encode_url(self.url), **self.kwargs) - async with r: - r.raise_for_status() - out = await r.read() - self.cache = AllBytes( - size=len(out), fetcher=None, blocksize=None, data=out - ) - self.size = len(out) - - _fetch_all = sync_wrapper(async_fetch_all) - - def _parse_content_range(self, headers): - """Parse the Content-Range header""" - s = headers.get("Content-Range", "") - m = re.match(r"bytes (\d+-\d+|\*)/(\d+|\*)", s) - if not m: - return None, None, None - - if m[1] == "*": - start = end = None - else: - start, end = [int(x) for x in m[1].split("-")] - total = None if m[2] == "*" else int(m[2]) - return start, end, total - - async def async_fetch_range(self, start, end): - """Download a block of data - - The expectation is that the server returns only the requested bytes, - with HTTP code 206. If this is not the case, we first check the headers, - and then stream the output - if the data size is bigger than we - requested, an exception is raised. - """ - logger.debug(f"Fetch range for {self}: {start}-{end}") - kwargs = self.kwargs.copy() - headers = kwargs.pop("headers", {}).copy() - headers["Range"] = f"bytes={start}-{end - 1}" - logger.debug(f"{self.url} : {headers['Range']}") - r = await self.session.get( - self.fs.encode_url(self.url), headers=headers, **kwargs - ) - async with r: - if r.status == 416: - # range request outside file - return b"" - r.raise_for_status() - - # If the server has handled the range request, it should reply - # with status 206 (partial content). But we'll guess that a suitable - # Content-Range header or a Content-Length no more than the - # requested range also mean we have got the desired range. - response_is_range = ( - r.status == 206 - or self._parse_content_range(r.headers)[0] == start - or int(r.headers.get("Content-Length", end + 1)) <= end - start - ) - - if response_is_range: - # partial content, as expected - out = await r.read() - elif start > 0: - raise ValueError( - "The HTTP server doesn't appear to support range requests. " - "Only reading this file from the beginning is supported. " - "Open with block_size=0 for a streaming file interface." - ) - else: - # Response is not a range, but we want the start of the file, - # so we can read the required amount anyway. - cl = 0 - out = [] - while True: - chunk = await r.content.read(2**20) - # data size unknown, let's read until we have enough - if chunk: - out.append(chunk) - cl += len(chunk) - if cl > end - start: - break - else: - break - out = b"".join(out)[: end - start] - return out - - _fetch_range = sync_wrapper(async_fetch_range) - - -magic_check = re.compile("([*[])") - - -def has_magic(s): - match = magic_check.search(s) - return match is not None - - -class HTTPStreamFile(AbstractBufferedFile): - def __init__(self, fs, url, mode="rb", loop=None, session=None, **kwargs): - self.asynchronous = kwargs.pop("asynchronous", False) - self.url = url - self.loop = loop - self.session = session - if mode != "rb": - raise ValueError - self.details = {"name": url, "size": None} - super().__init__(fs=fs, path=url, mode=mode, cache_type="none", **kwargs) - - async def cor(): - r = await self.session.get(self.fs.encode_url(url), **kwargs).__aenter__() - self.fs._raise_not_found_for_status(r, url) - return r - - self.r = sync(self.loop, cor) - self.loop = fs.loop - - def seek(self, loc, whence=0): - if loc == 0 and whence == 1: - return - if loc == self.loc and whence == 0: - return - raise ValueError("Cannot seek streaming HTTP file") - - async def _read(self, num=-1): - out = await self.r.content.read(num) - self.loc += len(out) - return out - - read = sync_wrapper(_read) - - async def _close(self): - self.r.close() - - def close(self): - asyncio.run_coroutine_threadsafe(self._close(), self.loop) - super().close() - - -class AsyncStreamFile(AbstractAsyncStreamedFile): - def __init__( - self, fs, url, mode="rb", loop=None, session=None, size=None, **kwargs - ): - self.url = url - self.session = session - self.r = None - if mode != "rb": - raise ValueError - self.details = {"name": url, "size": None} - self.kwargs = kwargs - super().__init__(fs=fs, path=url, mode=mode, cache_type="none") - self.size = size - - async def read(self, num=-1): - if self.r is None: - r = await self.session.get( - self.fs.encode_url(self.url), **self.kwargs - ).__aenter__() - self.fs._raise_not_found_for_status(r, self.url) - self.r = r - out = await self.r.content.read(num) - self.loc += len(out) - return out - - async def close(self): - if self.r is not None: - self.r.close() - self.r = None - await super().close() - - -async def get_range(session, url, start, end, file=None, **kwargs): - # explicit get a range when we know it must be safe - kwargs = kwargs.copy() - headers = kwargs.pop("headers", {}).copy() - headers["Range"] = f"bytes={start}-{end - 1}" - r = await session.get(url, headers=headers, **kwargs) - r.raise_for_status() - async with r: - out = await r.read() - if file: - with open(file, "r+b") as f: # noqa: ASYNC230 - f.seek(start) - f.write(out) - else: - return out - - -async def _file_info(url, session, size_policy="head", **kwargs): - """Call HEAD on the server to get details about the file (size/checksum etc.) - - Default operation is to explicitly allow redirects and use encoding - 'identity' (no compression) to get the true size of the target. - """ - logger.debug("Retrieve file size for %s", url) - kwargs = kwargs.copy() - ar = kwargs.pop("allow_redirects", True) - head = kwargs.get("headers", {}).copy() - head["Accept-Encoding"] = "identity" - kwargs["headers"] = head - - info = {} - if size_policy == "head": - r = await session.head(url, allow_redirects=ar, **kwargs) - elif size_policy == "get": - r = await session.get(url, allow_redirects=ar, **kwargs) - else: - raise TypeError(f'size_policy must be "head" or "get", got {size_policy}') - async with r: - r.raise_for_status() - - if "Content-Length" in r.headers: - # Some servers may choose to ignore Accept-Encoding and return - # compressed content, in which case the returned size is unreliable. - if "Content-Encoding" not in r.headers or r.headers["Content-Encoding"] in [ - "identity", - "", - ]: - info["size"] = int(r.headers["Content-Length"]) - elif "Content-Range" in r.headers: - info["size"] = int(r.headers["Content-Range"].split("/")[1]) - - if "Content-Type" in r.headers: - info["mimetype"] = r.headers["Content-Type"].partition(";")[0] - - if r.headers.get("Accept-Ranges") == "none": - # Some servers may explicitly discourage partial content requests, but - # the lack of "Accept-Ranges" does not always indicate they would fail - info["partial"] = False - - info["url"] = str(r.url) - - for checksum_field in ["ETag", "Content-MD5", "Digest", "Last-Modified"]: - if r.headers.get(checksum_field): - info[checksum_field] = r.headers[checksum_field] - - return info - - -async def _file_size(url, session=None, *args, **kwargs): - if session is None: - session = await get_client() - info = await _file_info(url, session=session, *args, **kwargs) - return info.get("size") - - -file_size = sync_wrapper(_file_size) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/http_sync.py b/venv/lib/python3.10/site-packages/fsspec/implementations/http_sync.py deleted file mode 100644 index a67ea3ea5fee9e6b51f7f3f66773e8cf65735e52..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/http_sync.py +++ /dev/null @@ -1,937 +0,0 @@ -"""This file is largely copied from http.py""" - -import io -import logging -import re -import urllib.error -import urllib.parse -from copy import copy -from json import dumps, loads -from urllib.parse import urlparse - -try: - import yarl -except (ImportError, ModuleNotFoundError, OSError): - yarl = False - -from fsspec.callbacks import _DEFAULT_CALLBACK -from fsspec.registry import register_implementation -from fsspec.spec import AbstractBufferedFile, AbstractFileSystem -from fsspec.utils import DEFAULT_BLOCK_SIZE, isfilelike, nullcontext, tokenize - -from ..caching import AllBytes - -# https://stackoverflow.com/a/15926317/3821154 -ex = re.compile(r"""<(a|A)\s+(?:[^>]*?\s+)?(href|HREF)=["'](?P[^"']+)""") -ex2 = re.compile(r"""(?Phttp[s]?://[-a-zA-Z0-9@:%_+.~#?&/=]+)""") -logger = logging.getLogger("fsspec.http") - - -class JsHttpException(urllib.error.HTTPError): ... - - -class StreamIO(io.BytesIO): - # fake class, so you can set attributes on it - # will eventually actually stream - ... - - -class ResponseProxy: - """Looks like a requests response""" - - def __init__(self, req, stream=False): - self.request = req - self.stream = stream - self._data = None - self._headers = None - - @property - def raw(self): - if self._data is None: - b = self.request.response.to_bytes() - if self.stream: - self._data = StreamIO(b) - else: - self._data = b - return self._data - - def close(self): - if hasattr(self, "_data"): - del self._data - - @property - def headers(self): - if self._headers is None: - self._headers = dict( - [ - _.split(": ") - for _ in self.request.getAllResponseHeaders().strip().split("\r\n") - ] - ) - return self._headers - - @property - def status_code(self): - return int(self.request.status) - - def raise_for_status(self): - if not self.ok: - raise JsHttpException( - self.url, self.status_code, self.reason, self.headers, None - ) - - def iter_content(self, chunksize, *_, **__): - while True: - out = self.raw.read(chunksize) - if out: - yield out - else: - break - - @property - def reason(self): - return self.request.statusText - - @property - def ok(self): - return self.status_code < 400 - - @property - def url(self): - return self.request.response.responseURL - - @property - def text(self): - # TODO: encoding from headers - return self.content.decode() - - @property - def content(self): - self.stream = False - return self.raw - - def json(self): - return loads(self.text) - - -class RequestsSessionShim: - def __init__(self): - self.headers = {} - - def request( - self, - method, - url, - params=None, - data=None, - headers=None, - cookies=None, - files=None, - auth=None, - timeout=None, - allow_redirects=None, - proxies=None, - hooks=None, - stream=None, - verify=None, - cert=None, - json=None, - ): - from js import Blob, XMLHttpRequest - - logger.debug("JS request: %s %s", method, url) - - if cert or verify or proxies or files or cookies or hooks: - raise NotImplementedError - if data and json: - raise ValueError("Use json= or data=, not both") - req = XMLHttpRequest.new() - extra = auth if auth else () - if params: - url = f"{url}?{urllib.parse.urlencode(params)}" - req.open(method, url, False, *extra) - if timeout: - req.timeout = timeout - if headers: - for k, v in headers.items(): - req.setRequestHeader(k, v) - - req.setRequestHeader("Accept", "application/octet-stream") - req.responseType = "arraybuffer" - if json: - blob = Blob.new([dumps(data)], {type: "application/json"}) - req.send(blob) - elif data: - if isinstance(data, io.IOBase): - data = data.read() - blob = Blob.new([data], {type: "application/octet-stream"}) - req.send(blob) - else: - req.send(None) - return ResponseProxy(req, stream=stream) - - def get(self, url, **kwargs): - return self.request("GET", url, **kwargs) - - def head(self, url, **kwargs): - return self.request("HEAD", url, **kwargs) - - def post(self, url, **kwargs): - return self.request("POST}", url, **kwargs) - - def put(self, url, **kwargs): - return self.request("PUT", url, **kwargs) - - def patch(self, url, **kwargs): - return self.request("PATCH", url, **kwargs) - - def delete(self, url, **kwargs): - return self.request("DELETE", url, **kwargs) - - -class HTTPFileSystem(AbstractFileSystem): - """ - Simple File-System for fetching data via HTTP(S) - - This is the BLOCKING version of the normal HTTPFileSystem. It uses - requests in normal python and the JS runtime in pyodide. - - ***This implementation is extremely experimental, do not use unless - you are testing pyodide/pyscript integration*** - """ - - protocol = ("http", "https", "sync-http", "sync-https") - sep = "/" - - def __init__( - self, - simple_links=True, - block_size=None, - same_scheme=True, - cache_type="readahead", - cache_options=None, - client_kwargs=None, - encoded=False, - **storage_options, - ): - """ - - Parameters - ---------- - block_size: int - Blocks to read bytes; if 0, will default to raw requests file-like - objects instead of HTTPFile instances - simple_links: bool - If True, will consider both HTML tags and anything that looks - like a URL; if False, will consider only the former. - same_scheme: True - When doing ls/glob, if this is True, only consider paths that have - http/https matching the input URLs. - size_policy: this argument is deprecated - client_kwargs: dict - Passed to aiohttp.ClientSession, see - https://docs.aiohttp.org/en/stable/client_reference.html - For example, ``{'auth': aiohttp.BasicAuth('user', 'pass')}`` - storage_options: key-value - Any other parameters passed on to requests - cache_type, cache_options: defaults used in open - """ - super().__init__(self, **storage_options) - self.block_size = block_size if block_size is not None else DEFAULT_BLOCK_SIZE - self.simple_links = simple_links - self.same_schema = same_scheme - self.cache_type = cache_type - self.cache_options = cache_options - self.client_kwargs = client_kwargs or {} - self.encoded = encoded - self.kwargs = storage_options - - try: - import js # noqa: F401 - - logger.debug("Starting JS session") - self.session = RequestsSessionShim() - self.js = True - except Exception as e: - import requests - - logger.debug("Starting cpython session because of: %s", e) - self.session = requests.Session(**(client_kwargs or {})) - self.js = False - - request_options = copy(storage_options) - self.use_listings_cache = request_options.pop("use_listings_cache", False) - request_options.pop("listings_expiry_time", None) - request_options.pop("max_paths", None) - request_options.pop("skip_instance_cache", None) - self.kwargs = request_options - - @property - def fsid(self): - return "sync-http" - - def encode_url(self, url): - if yarl: - return yarl.URL(url, encoded=self.encoded) - return url - - @classmethod - def _strip_protocol(cls, path: str) -> str: - """For HTTP, we always want to keep the full URL""" - path = path.replace("sync-http://", "http://").replace( - "sync-https://", "https://" - ) - return path - - @classmethod - def _parent(cls, path): - # override, since _strip_protocol is different for URLs - par = super()._parent(path) - if len(par) > 7: # "http://..." - return par - return "" - - def _ls_real(self, url, detail=True, **kwargs): - # ignoring URL-encoded arguments - kw = self.kwargs.copy() - kw.update(kwargs) - logger.debug(url) - r = self.session.get(self.encode_url(url), **self.kwargs) - self._raise_not_found_for_status(r, url) - text = r.text - if self.simple_links: - links = ex2.findall(text) + [u[2] for u in ex.findall(text)] - else: - links = [u[2] for u in ex.findall(text)] - out = set() - parts = urlparse(url) - for l in links: - if isinstance(l, tuple): - l = l[1] - if l.startswith("/") and len(l) > 1: - # absolute URL on this server - l = parts.scheme + "://" + parts.netloc + l - if l.startswith("http"): - if self.same_schema and l.startswith(url.rstrip("/") + "/"): - out.add(l) - elif l.replace("https", "http").startswith( - url.replace("https", "http").rstrip("/") + "/" - ): - # allowed to cross http <-> https - out.add(l) - else: - if l not in ["..", "../"]: - # Ignore FTP-like "parent" - out.add("/".join([url.rstrip("/"), l.lstrip("/")])) - if not out and url.endswith("/"): - out = self._ls_real(url.rstrip("/"), detail=False) - if detail: - return [ - { - "name": u, - "size": None, - "type": "directory" if u.endswith("/") else "file", - } - for u in out - ] - else: - return sorted(out) - - def ls(self, url, detail=True, **kwargs): - if self.use_listings_cache and url in self.dircache: - out = self.dircache[url] - else: - out = self._ls_real(url, detail=detail, **kwargs) - self.dircache[url] = out - return out - - def _raise_not_found_for_status(self, response, url): - """ - Raises FileNotFoundError for 404s, otherwise uses raise_for_status. - """ - if response.status_code == 404: - raise FileNotFoundError(url) - response.raise_for_status() - - def cat_file(self, url, start=None, end=None, **kwargs): - kw = self.kwargs.copy() - kw.update(kwargs) - logger.debug(url) - - if start is not None or end is not None: - if start == end: - return b"" - headers = kw.pop("headers", {}).copy() - - headers["Range"] = self._process_limits(url, start, end) - kw["headers"] = headers - r = self.session.get(self.encode_url(url), **kw) - self._raise_not_found_for_status(r, url) - return r.content - - def get_file( - self, rpath, lpath, chunk_size=5 * 2**20, callback=_DEFAULT_CALLBACK, **kwargs - ): - kw = self.kwargs.copy() - kw.update(kwargs) - logger.debug(rpath) - r = self.session.get(self.encode_url(rpath), **kw) - try: - size = int( - r.headers.get("content-length", None) - or r.headers.get("Content-Length", None) - ) - except (ValueError, KeyError, TypeError): - size = None - - callback.set_size(size) - self._raise_not_found_for_status(r, rpath) - if not isfilelike(lpath): - lpath = open(lpath, "wb") - for chunk in r.iter_content(chunk_size, decode_unicode=False): - lpath.write(chunk) - callback.relative_update(len(chunk)) - - def put_file( - self, - lpath, - rpath, - chunk_size=5 * 2**20, - callback=_DEFAULT_CALLBACK, - method="post", - **kwargs, - ): - def gen_chunks(): - # Support passing arbitrary file-like objects - # and use them instead of streams. - if isinstance(lpath, io.IOBase): - context = nullcontext(lpath) - use_seek = False # might not support seeking - else: - context = open(lpath, "rb") - use_seek = True - - with context as f: - if use_seek: - callback.set_size(f.seek(0, 2)) - f.seek(0) - else: - callback.set_size(getattr(f, "size", None)) - - chunk = f.read(chunk_size) - while chunk: - yield chunk - callback.relative_update(len(chunk)) - chunk = f.read(chunk_size) - - kw = self.kwargs.copy() - kw.update(kwargs) - - method = method.lower() - if method not in ("post", "put"): - raise ValueError( - f"method has to be either 'post' or 'put', not: {method!r}" - ) - - meth = getattr(self.session, method) - resp = meth(rpath, data=gen_chunks(), **kw) - self._raise_not_found_for_status(resp, rpath) - - def _process_limits(self, url, start, end): - """Helper for "Range"-based _cat_file""" - size = None - suff = False - if start is not None and start < 0: - # if start is negative and end None, end is the "suffix length" - if end is None: - end = -start - start = "" - suff = True - else: - size = size or self.info(url)["size"] - start = size + start - elif start is None: - start = 0 - if not suff: - if end is not None and end < 0: - if start is not None: - size = size or self.info(url)["size"] - end = size + end - elif end is None: - end = "" - if isinstance(end, int): - end -= 1 # bytes range is inclusive - return f"bytes={start}-{end}" - - def exists(self, path, strict=False, **kwargs): - kw = self.kwargs.copy() - kw.update(kwargs) - try: - logger.debug(path) - r = self.session.get(self.encode_url(path), **kw) - if strict: - self._raise_not_found_for_status(r, path) - return r.status_code < 400 - except FileNotFoundError: - return False - except Exception: - if strict: - raise - return False - - def isfile(self, path, **kwargs): - return self.exists(path, **kwargs) - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=None, # XXX: This differs from the base class. - cache_type=None, - cache_options=None, - size=None, - **kwargs, - ): - """Make a file-like object - - Parameters - ---------- - path: str - Full URL with protocol - mode: string - must be "rb" - block_size: int or None - Bytes to download in one request; use instance value if None. If - zero, will return a streaming Requests file-like instance. - kwargs: key-value - Any other parameters, passed to requests calls - """ - if mode != "rb": - raise NotImplementedError - block_size = block_size if block_size is not None else self.block_size - kw = self.kwargs.copy() - kw.update(kwargs) - size = size or self.info(path, **kwargs)["size"] - if block_size and size: - return HTTPFile( - self, - path, - session=self.session, - block_size=block_size, - mode=mode, - size=size, - cache_type=cache_type or self.cache_type, - cache_options=cache_options or self.cache_options, - **kw, - ) - else: - return HTTPStreamFile( - self, - path, - mode=mode, - session=self.session, - **kw, - ) - - def ukey(self, url): - """Unique identifier; assume HTTP files are static, unchanging""" - return tokenize(url, self.kwargs, self.protocol) - - def info(self, url, **kwargs): - """Get info of URL - - Tries to access location via HEAD, and then GET methods, but does - not fetch the data. - - It is possible that the server does not supply any size information, in - which case size will be given as None (and certain operations on the - corresponding file will not work). - """ - info = {} - for policy in ["head", "get"]: - try: - info.update( - _file_info( - self.encode_url(url), - size_policy=policy, - session=self.session, - **self.kwargs, - **kwargs, - ) - ) - if info.get("size") is not None: - break - except Exception as exc: - if policy == "get": - # If get failed, then raise a FileNotFoundError - raise FileNotFoundError(url) from exc - logger.debug(str(exc)) - - return {"name": url, "size": None, **info, "type": "file"} - - def glob(self, path, maxdepth=None, **kwargs): - """ - Find files by glob-matching. - - This implementation is idntical to the one in AbstractFileSystem, - but "?" is not considered as a character for globbing, because it is - so common in URLs, often identifying the "query" part. - """ - import re - - ends = path.endswith("/") - path = self._strip_protocol(path) - indstar = path.find("*") if path.find("*") >= 0 else len(path) - indbrace = path.find("[") if path.find("[") >= 0 else len(path) - - ind = min(indstar, indbrace) - - detail = kwargs.pop("detail", False) - - if not has_magic(path): - root = path - depth = 1 - if ends: - path += "/*" - elif self.exists(path): - if not detail: - return [path] - else: - return {path: self.info(path)} - else: - if not detail: - return [] # glob of non-existent returns empty - else: - return {} - elif "/" in path[:ind]: - ind2 = path[:ind].rindex("/") - root = path[: ind2 + 1] - depth = None if "**" in path else path[ind2 + 1 :].count("/") + 1 - else: - root = "" - depth = None if "**" in path else path[ind + 1 :].count("/") + 1 - - allpaths = self.find( - root, maxdepth=maxdepth or depth, withdirs=True, detail=True, **kwargs - ) - # Escape characters special to python regex, leaving our supported - # special characters in place. - # See https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html - # for shell globbing details. - pattern = ( - "^" - + ( - path.replace("\\", r"\\") - .replace(".", r"\.") - .replace("+", r"\+") - .replace("//", "/") - .replace("(", r"\(") - .replace(")", r"\)") - .replace("|", r"\|") - .replace("^", r"\^") - .replace("$", r"\$") - .replace("{", r"\{") - .replace("}", r"\}") - .rstrip("/") - ) - + "$" - ) - pattern = re.sub("[*]{2}", "=PLACEHOLDER=", pattern) - pattern = re.sub("[*]", "[^/]*", pattern) - pattern = re.compile(pattern.replace("=PLACEHOLDER=", ".*")) - out = { - p: allpaths[p] - for p in sorted(allpaths) - if pattern.match(p.replace("//", "/").rstrip("/")) - } - if detail: - return out - else: - return list(out) - - def isdir(self, path): - # override, since all URLs are (also) files - try: - return bool(self.ls(path)) - except (FileNotFoundError, ValueError): - return False - - -class HTTPFile(AbstractBufferedFile): - """ - A file-like object pointing to a remove HTTP(S) resource - - Supports only reading, with read-ahead of a predermined block-size. - - In the case that the server does not supply the filesize, only reading of - the complete file in one go is supported. - - Parameters - ---------- - url: str - Full URL of the remote resource, including the protocol - session: requests.Session or None - All calls will be made within this session, to avoid restarting - connections where the server allows this - block_size: int or None - The amount of read-ahead to do, in bytes. Default is 5MB, or the value - configured for the FileSystem creating this file - size: None or int - If given, this is the size of the file in bytes, and we don't attempt - to call the server to find the value. - kwargs: all other key-values are passed to requests calls. - """ - - def __init__( - self, - fs, - url, - session=None, - block_size=None, - mode="rb", - cache_type="bytes", - cache_options=None, - size=None, - **kwargs, - ): - if mode != "rb": - raise NotImplementedError("File mode not supported") - self.url = url - self.session = session - self.details = {"name": url, "size": size, "type": "file"} - super().__init__( - fs=fs, - path=url, - mode=mode, - block_size=block_size, - cache_type=cache_type, - cache_options=cache_options, - **kwargs, - ) - - def read(self, length=-1): - """Read bytes from file - - Parameters - ---------- - length: int - Read up to this many bytes. If negative, read all content to end of - file. If the server has not supplied the filesize, attempting to - read only part of the data will raise a ValueError. - """ - if ( - (length < 0 and self.loc == 0) # explicit read all - # but not when the size is known and fits into a block anyways - and not (self.size is not None and self.size <= self.blocksize) - ): - self._fetch_all() - if self.size is None: - if length < 0: - self._fetch_all() - else: - length = min(self.size - self.loc, length) - return super().read(length) - - def _fetch_all(self): - """Read whole file in one shot, without caching - - This is only called when position is still at zero, - and read() is called without a byte-count. - """ - logger.debug(f"Fetch all for {self}") - if not isinstance(self.cache, AllBytes): - r = self.session.get(self.fs.encode_url(self.url), **self.kwargs) - r.raise_for_status() - out = r.content - self.cache = AllBytes(size=len(out), fetcher=None, blocksize=None, data=out) - self.size = len(out) - - def _parse_content_range(self, headers): - """Parse the Content-Range header""" - s = headers.get("Content-Range", "") - m = re.match(r"bytes (\d+-\d+|\*)/(\d+|\*)", s) - if not m: - return None, None, None - - if m[1] == "*": - start = end = None - else: - start, end = [int(x) for x in m[1].split("-")] - total = None if m[2] == "*" else int(m[2]) - return start, end, total - - def _fetch_range(self, start, end): - """Download a block of data - - The expectation is that the server returns only the requested bytes, - with HTTP code 206. If this is not the case, we first check the headers, - and then stream the output - if the data size is bigger than we - requested, an exception is raised. - """ - logger.debug(f"Fetch range for {self}: {start}-{end}") - kwargs = self.kwargs.copy() - headers = kwargs.pop("headers", {}).copy() - headers["Range"] = f"bytes={start}-{end - 1}" - logger.debug("%s : %s", self.url, headers["Range"]) - r = self.session.get(self.fs.encode_url(self.url), headers=headers, **kwargs) - if r.status_code == 416: - # range request outside file - return b"" - r.raise_for_status() - - # If the server has handled the range request, it should reply - # with status 206 (partial content). But we'll guess that a suitable - # Content-Range header or a Content-Length no more than the - # requested range also mean we have got the desired range. - cl = r.headers.get("Content-Length", r.headers.get("content-length", end + 1)) - response_is_range = ( - r.status_code == 206 - or self._parse_content_range(r.headers)[0] == start - or int(cl) <= end - start - ) - - if response_is_range: - # partial content, as expected - out = r.content - elif start > 0: - raise ValueError( - "The HTTP server doesn't appear to support range requests. " - "Only reading this file from the beginning is supported. " - "Open with block_size=0 for a streaming file interface." - ) - else: - # Response is not a range, but we want the start of the file, - # so we can read the required amount anyway. - cl = 0 - out = [] - for chunk in r.iter_content(2**20, False): - out.append(chunk) - cl += len(chunk) - out = b"".join(out)[: end - start] - return out - - -magic_check = re.compile("([*[])") - - -def has_magic(s): - match = magic_check.search(s) - return match is not None - - -class HTTPStreamFile(AbstractBufferedFile): - def __init__(self, fs, url, mode="rb", session=None, **kwargs): - self.url = url - self.session = session - if mode != "rb": - raise ValueError - self.details = {"name": url, "size": None} - super().__init__(fs=fs, path=url, mode=mode, cache_type="readahead", **kwargs) - - r = self.session.get(self.fs.encode_url(url), stream=True, **kwargs) - self.fs._raise_not_found_for_status(r, url) - self.it = r.iter_content(1024, False) - self.leftover = b"" - - self.r = r - - def seek(self, *args, **kwargs): - raise ValueError("Cannot seek streaming HTTP file") - - def read(self, num=-1): - bufs = [self.leftover] - leng = len(self.leftover) - while leng < num or num < 0: - try: - out = self.it.__next__() - except StopIteration: - break - if out: - bufs.append(out) - else: - break - leng += len(out) - out = b"".join(bufs) - if num >= 0: - self.leftover = out[num:] - out = out[:num] - else: - self.leftover = b"" - self.loc += len(out) - return out - - def close(self): - self.r.close() - self.closed = True - - -def get_range(session, url, start, end, **kwargs): - # explicit get a range when we know it must be safe - kwargs = kwargs.copy() - headers = kwargs.pop("headers", {}).copy() - headers["Range"] = f"bytes={start}-{end - 1}" - r = session.get(url, headers=headers, **kwargs) - r.raise_for_status() - return r.content - - -def _file_info(url, session, size_policy="head", **kwargs): - """Call HEAD on the server to get details about the file (size/checksum etc.) - - Default operation is to explicitly allow redirects and use encoding - 'identity' (no compression) to get the true size of the target. - """ - logger.debug("Retrieve file size for %s", url) - kwargs = kwargs.copy() - ar = kwargs.pop("allow_redirects", True) - head = kwargs.get("headers", {}).copy() - # TODO: not allowed in JS - # head["Accept-Encoding"] = "identity" - kwargs["headers"] = head - - info = {} - if size_policy == "head": - r = session.head(url, allow_redirects=ar, **kwargs) - elif size_policy == "get": - r = session.get(url, allow_redirects=ar, **kwargs) - else: - raise TypeError(f'size_policy must be "head" or "get", got {size_policy}') - r.raise_for_status() - - # TODO: - # recognise lack of 'Accept-Ranges', - # or 'Accept-Ranges': 'none' (not 'bytes') - # to mean streaming only, no random access => return None - if "Content-Length" in r.headers: - info["size"] = int(r.headers["Content-Length"]) - elif "Content-Range" in r.headers: - info["size"] = int(r.headers["Content-Range"].split("/")[1]) - elif "content-length" in r.headers: - info["size"] = int(r.headers["content-length"]) - elif "content-range" in r.headers: - info["size"] = int(r.headers["content-range"].split("/")[1]) - - for checksum_field in ["ETag", "Content-MD5", "Digest"]: - if r.headers.get(checksum_field): - info[checksum_field] = r.headers[checksum_field] - - return info - - -# importing this is enough to register it -def register(): - register_implementation("http", HTTPFileSystem, clobber=True) - register_implementation("https", HTTPFileSystem, clobber=True) - register_implementation("sync-http", HTTPFileSystem, clobber=True) - register_implementation("sync-https", HTTPFileSystem, clobber=True) - - -register() - - -def unregister(): - from fsspec.implementations.http import HTTPFileSystem - - register_implementation("http", HTTPFileSystem, clobber=True) - register_implementation("https", HTTPFileSystem, clobber=True) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/jupyter.py b/venv/lib/python3.10/site-packages/fsspec/implementations/jupyter.py deleted file mode 100644 index e5571ed56582170051f3b7cd903093eed4c65244..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/jupyter.py +++ /dev/null @@ -1,129 +0,0 @@ -import base64 -import io -import re - -import requests - -import fsspec - - -class JupyterFileSystem(fsspec.AbstractFileSystem): - """View of the files as seen by a Jupyter server (notebook or lab)""" - - protocol = ("jupyter", "jlab") - - def __init__(self, url, tok=None, **kwargs): - """ - - Parameters - ---------- - url : str - Base URL of the server, like "http://127.0.0.1:8888". May include - token in the string, which is given by the process when starting up - tok : str - If the token is obtained separately, can be given here - kwargs - """ - if "?" in url: - if tok is None: - try: - tok = re.findall("token=([a-z0-9]+)", url)[0] - except IndexError as e: - raise ValueError("Could not determine token") from e - url = url.split("?", 1)[0] - self.url = url.rstrip("/") + "/api/contents" - self.session = requests.Session() - if tok: - self.session.headers["Authorization"] = f"token {tok}" - - super().__init__(**kwargs) - - def ls(self, path, detail=True, **kwargs): - path = self._strip_protocol(path) - r = self.session.get(f"{self.url}/{path}") - if r.status_code == 404: - raise FileNotFoundError(path) - r.raise_for_status() - out = r.json() - - if out["type"] == "directory": - out = out["content"] - else: - out = [out] - for o in out: - o["name"] = o.pop("path") - o.pop("content") - if o["type"] == "notebook": - o["type"] = "file" - if detail: - return out - return [o["name"] for o in out] - - def cat_file(self, path, start=None, end=None, **kwargs): - path = self._strip_protocol(path) - r = self.session.get(f"{self.url}/{path}") - if r.status_code == 404: - raise FileNotFoundError(path) - r.raise_for_status() - out = r.json() - if out["format"] == "text": - # data should be binary - b = out["content"].encode() - else: - b = base64.b64decode(out["content"]) - return b[start:end] - - def pipe_file(self, path, value, **_): - path = self._strip_protocol(path) - json = { - "name": path.rsplit("/", 1)[-1], - "path": path, - "size": len(value), - "content": base64.b64encode(value).decode(), - "format": "base64", - "type": "file", - } - self.session.put(f"{self.url}/{path}", json=json) - - def mkdir(self, path, create_parents=True, **kwargs): - path = self._strip_protocol(path) - if create_parents and "/" in path: - self.mkdir(path.rsplit("/", 1)[0], True) - json = { - "name": path.rsplit("/", 1)[-1], - "path": path, - "size": None, - "content": None, - "type": "directory", - } - self.session.put(f"{self.url}/{path}", json=json) - - def mv(self, path1, path2, recursive=False, maxdepth=None, **kwargs): - if path1 == path2: - return - self.session.patch(f"{self.url}/{path1}", json={"path": path2}) - - def _rm(self, path): - path = self._strip_protocol(path) - self.session.delete(f"{self.url}/{path}") - - def _open(self, path, mode="rb", **kwargs): - path = self._strip_protocol(path) - if mode == "rb": - data = self.cat_file(path) - return io.BytesIO(data) - else: - return SimpleFileWriter(self, path, mode="wb") - - -class SimpleFileWriter(fsspec.spec.AbstractBufferedFile): - def _upload_chunk(self, final=False): - """Never uploads a chunk until file is done - - Not suitable for large files - """ - if final is False: - return False - self.buffer.seek(0) - data = self.buffer.read() - self.fs.pipe_file(self.path, data) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/libarchive.py b/venv/lib/python3.10/site-packages/fsspec/implementations/libarchive.py deleted file mode 100644 index 6f8e750002df72865d611b48022e6634f9572614..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/libarchive.py +++ /dev/null @@ -1,213 +0,0 @@ -from contextlib import contextmanager -from ctypes import ( - CFUNCTYPE, - POINTER, - c_int, - c_longlong, - c_void_p, - cast, - create_string_buffer, -) - -import libarchive -import libarchive.ffi as ffi - -from fsspec import open_files -from fsspec.archive import AbstractArchiveFileSystem -from fsspec.implementations.memory import MemoryFile -from fsspec.utils import DEFAULT_BLOCK_SIZE - -# Libarchive requires seekable files or memory only for certain archive -# types. However, since we read the directory first to cache the contents -# and also allow random access to any file, the file-like object needs -# to be seekable no matter what. - -# Seek call-backs (not provided in the libarchive python wrapper) -SEEK_CALLBACK = CFUNCTYPE(c_longlong, c_int, c_void_p, c_longlong, c_int) -read_set_seek_callback = ffi.ffi( - "read_set_seek_callback", [ffi.c_archive_p, SEEK_CALLBACK], c_int, ffi.check_int -) -new_api = hasattr(ffi, "NO_OPEN_CB") - - -@contextmanager -def custom_reader(file, format_name="all", filter_name="all", block_size=ffi.page_size): - """Read an archive from a seekable file-like object. - - The `file` object must support the standard `readinto` and 'seek' methods. - """ - buf = create_string_buffer(block_size) - buf_p = cast(buf, c_void_p) - - def read_func(archive_p, context, ptrptr): - # readinto the buffer, returns number of bytes read - length = file.readinto(buf) - # write the address of the buffer into the pointer - ptrptr = cast(ptrptr, POINTER(c_void_p)) - ptrptr[0] = buf_p - # tell libarchive how much data was written into the buffer - return length - - def seek_func(archive_p, context, offset, whence): - file.seek(offset, whence) - # tell libarchvie the current position - return file.tell() - - read_cb = ffi.READ_CALLBACK(read_func) - seek_cb = SEEK_CALLBACK(seek_func) - - if new_api: - open_cb = ffi.NO_OPEN_CB - close_cb = ffi.NO_CLOSE_CB - else: - open_cb = libarchive.read.OPEN_CALLBACK(ffi.VOID_CB) - close_cb = libarchive.read.CLOSE_CALLBACK(ffi.VOID_CB) - - with libarchive.read.new_archive_read(format_name, filter_name) as archive_p: - read_set_seek_callback(archive_p, seek_cb) - ffi.read_open(archive_p, None, open_cb, read_cb, close_cb) - yield libarchive.read.ArchiveRead(archive_p) - - -class LibArchiveFileSystem(AbstractArchiveFileSystem): - """Compressed archives as a file-system (read-only) - - Supports the following formats: - tar, pax , cpio, ISO9660, zip, mtree, shar, ar, raw, xar, lha/lzh, rar - Microsoft CAB, 7-Zip, WARC - - See the libarchive documentation for further restrictions. - https://www.libarchive.org/ - - Keeps file object open while instance lives. It only works in seekable - file-like objects. In case the filesystem does not support this kind of - file object, it is recommended to cache locally. - - This class is pickleable, but not necessarily thread-safe (depends on the - platform). See libarchive documentation for details. - """ - - root_marker = "" - protocol = "libarchive" - cachable = False - - def __init__( - self, - fo="", - mode="r", - target_protocol=None, - target_options=None, - block_size=DEFAULT_BLOCK_SIZE, - **kwargs, - ): - """ - Parameters - ---------- - fo: str or file-like - Contains ZIP, and must exist. If a str, will fetch file using - :meth:`~fsspec.open_files`, which must return one file exactly. - mode: str - Currently, only 'r' accepted - target_protocol: str (optional) - If ``fo`` is a string, this value can be used to override the - FS protocol inferred from a URL - target_options: dict (optional) - Kwargs passed when instantiating the target FS, if ``fo`` is - a string. - """ - super().__init__(self, **kwargs) - if mode != "r": - raise ValueError("Only read from archive files accepted") - if isinstance(fo, str): - files = open_files(fo, protocol=target_protocol, **(target_options or {})) - if len(files) != 1: - raise ValueError( - f'Path "{fo}" did not resolve to exactly one file: "{files}"' - ) - fo = files[0] - self.of = fo - self.fo = fo.__enter__() # the whole instance is a context - self.block_size = block_size - self.dir_cache = None - - @contextmanager - def _open_archive(self): - self.fo.seek(0) - with custom_reader(self.fo, block_size=self.block_size) as arc: - yield arc - - @classmethod - def _strip_protocol(cls, path): - # file paths are always relative to the archive root - return super()._strip_protocol(path).lstrip("/") - - def _get_dirs(self): - fields = { - "name": "pathname", - "size": "size", - "created": "ctime", - "mode": "mode", - "uid": "uid", - "gid": "gid", - "mtime": "mtime", - } - - if self.dir_cache is not None: - return - - self.dir_cache = {} - list_names = [] - with self._open_archive() as arc: - for entry in arc: - if not entry.isdir and not entry.isfile: - # Skip symbolic links, fifo entries, etc. - continue - self.dir_cache.update( - { - dirname: {"name": dirname, "size": 0, "type": "directory"} - for dirname in self._all_dirnames(set(entry.name)) - } - ) - f = {key: getattr(entry, fields[key]) for key in fields} - f["type"] = "directory" if entry.isdir else "file" - list_names.append(entry.name) - - self.dir_cache[f["name"]] = f - # libarchive does not seem to return an entry for the directories (at least - # not in all formats), so get the directories names from the files names - self.dir_cache.update( - { - dirname: {"name": dirname, "size": 0, "type": "directory"} - for dirname in self._all_dirnames(list_names) - } - ) - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - **kwargs, - ): - path = self._strip_protocol(path) - if mode != "rb": - raise NotImplementedError - - data = b"" - with self._open_archive() as arc: - for entry in arc: - if entry.pathname != path: - continue - - if entry.size == 0: - # empty file, so there are no blocks - break - - for block in entry.get_blocks(entry.size): - data = block - break - else: - raise ValueError - return MemoryFile(fs=self, path=path, data=data) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/local.py b/venv/lib/python3.10/site-packages/fsspec/implementations/local.py deleted file mode 100644 index 417447e5bed17525fe89985052b8c2d8319e1aa6..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/local.py +++ /dev/null @@ -1,518 +0,0 @@ -import datetime -import io -import logging -import os -import os.path as osp -import shutil -import stat -import tempfile -from functools import lru_cache - -from fsspec import AbstractFileSystem -from fsspec.compression import compr -from fsspec.core import get_compression -from fsspec.utils import isfilelike, stringify_path - -logger = logging.getLogger("fsspec.local") - - -class LocalFileSystem(AbstractFileSystem): - """Interface to files on local storage - - Parameters - ---------- - auto_mkdir: bool - Whether, when opening a file, the directory containing it should - be created (if it doesn't already exist). This is assumed by pyarrow - code. - """ - - root_marker = "/" - protocol = "file", "local" - local_file = True - - def __init__(self, auto_mkdir=False, **kwargs): - super().__init__(**kwargs) - self.auto_mkdir = auto_mkdir - - @property - def fsid(self): - return "local" - - def mkdir(self, path, create_parents=True, **kwargs): - path = self._strip_protocol(path) - if self.exists(path): - raise FileExistsError(path) - if create_parents: - self.makedirs(path, exist_ok=True) - else: - os.mkdir(path, **kwargs) - - def makedirs(self, path, exist_ok=False): - path = self._strip_protocol(path) - os.makedirs(path, exist_ok=exist_ok) - - def rmdir(self, path): - path = self._strip_protocol(path) - os.rmdir(path) - - def ls(self, path, detail=False, **kwargs): - path = self._strip_protocol(path) - path_info = self.info(path) - infos = [] - if path_info["type"] == "directory": - with os.scandir(path) as it: - for f in it: - try: - # Only get the info if requested since it is a bit expensive (the stat call inside) - # The strip_protocol is also used in info() and calls make_path_posix to always return posix paths - info = self.info(f) if detail else self._strip_protocol(f.path) - infos.append(info) - except FileNotFoundError: - pass - else: - infos = [path_info] if detail else [path_info["name"]] - - return infos - - def info(self, path, **kwargs): - if isinstance(path, os.DirEntry): - # scandir DirEntry - out = path.stat(follow_symlinks=False) - link = path.is_symlink() - if path.is_dir(follow_symlinks=False): - t = "directory" - elif path.is_file(follow_symlinks=False): - t = "file" - else: - t = "other" - - size = out.st_size - if link: - try: - out2 = path.stat(follow_symlinks=True) - size = out2.st_size - except OSError: - size = 0 - path = self._strip_protocol(path.path) - else: - # str or path-like - path = self._strip_protocol(path) - out = os.stat(path, follow_symlinks=False) - link = stat.S_ISLNK(out.st_mode) - if link: - out = os.stat(path, follow_symlinks=True) - size = out.st_size - if stat.S_ISDIR(out.st_mode): - t = "directory" - elif stat.S_ISREG(out.st_mode): - t = "file" - else: - t = "other" - - # Check for the 'st_birthtime' attribute, which is not always present; fallback to st_ctime - created_time = getattr(out, "st_birthtime", out.st_ctime) - - result = { - "name": path, - "size": size, - "type": t, - "created": created_time, - "islink": link, - } - for field in ["mode", "uid", "gid", "mtime", "ino", "nlink"]: - result[field] = getattr(out, f"st_{field}") - if link: - result["destination"] = os.readlink(path) - return result - - def lexists(self, path, **kwargs): - return osp.lexists(path) - - def cp_file(self, path1, path2, **kwargs): - path1 = self._strip_protocol(path1) - path2 = self._strip_protocol(path2) - if self.auto_mkdir: - self.makedirs(self._parent(path2), exist_ok=True) - if self.isfile(path1): - shutil.copyfile(path1, path2) - elif self.isdir(path1): - self.mkdirs(path2, exist_ok=True) - else: - raise FileNotFoundError(path1) - - def isfile(self, path): - path = self._strip_protocol(path) - return os.path.isfile(path) - - def isdir(self, path): - path = self._strip_protocol(path) - return os.path.isdir(path) - - def get_file(self, path1, path2, callback=None, **kwargs): - if isfilelike(path2): - with open(path1, "rb") as f: - shutil.copyfileobj(f, path2) - else: - return self.cp_file(path1, path2, **kwargs) - - def put_file(self, path1, path2, callback=None, **kwargs): - return self.cp_file(path1, path2, **kwargs) - - def mv(self, path1, path2, recursive: bool = True, **kwargs): - """Move files/directories - For the specific case of local, all ops on directories are recursive and - the recursive= kwarg is ignored. - """ - path1 = self._strip_protocol(path1) - path2 = self._strip_protocol(path2) - - if self.auto_mkdir: - self.makedirs(self._parent(path2), exist_ok=True) - - shutil.move(path1, path2) - - def link(self, src, dst, **kwargs): - src = self._strip_protocol(src) - dst = self._strip_protocol(dst) - os.link(src, dst, **kwargs) - - def symlink(self, src, dst, **kwargs): - src = self._strip_protocol(src) - dst = self._strip_protocol(dst) - os.symlink(src, dst, **kwargs) - - def islink(self, path) -> bool: - return os.path.islink(self._strip_protocol(path)) - - def rm_file(self, path): - os.remove(self._strip_protocol(path)) - - def rm(self, path, recursive=False, maxdepth=None): - if not isinstance(path, list): - path = [path] - - for p in path: - p = self._strip_protocol(p) - if self.isdir(p): - if not recursive: - raise ValueError("Cannot delete directory, set recursive=True") - if osp.abspath(p) == os.getcwd(): - raise ValueError("Cannot delete current working directory") - shutil.rmtree(p) - else: - os.remove(p) - - def unstrip_protocol(self, name): - name = self._strip_protocol(name) # normalise for local/win/... - return f"file://{name}" - - def _open(self, path, mode="rb", block_size=None, **kwargs): - path = self._strip_protocol(path) - if self.auto_mkdir and "w" in mode: - self.makedirs(self._parent(path), exist_ok=True) - return LocalFileOpener(path, mode, fs=self, **kwargs) - - def touch(self, path, truncate=True, **kwargs): - path = self._strip_protocol(path) - if self.auto_mkdir: - self.makedirs(self._parent(path), exist_ok=True) - if self.exists(path): - os.utime(path, None) - else: - open(path, "a").close() - if truncate: - os.truncate(path, 0) - - def created(self, path): - info = self.info(path=path) - return datetime.datetime.fromtimestamp( - info["created"], tz=datetime.timezone.utc - ) - - def modified(self, path): - info = self.info(path=path) - return datetime.datetime.fromtimestamp(info["mtime"], tz=datetime.timezone.utc) - - @classmethod - def _parent(cls, path): - path = cls._strip_protocol(path) - if os.sep == "/": - # posix native - return path.rsplit("/", 1)[0] or "/" - else: - # NT - path_ = path.rsplit("/", 1)[0] - if len(path_) <= 3: - if path_[1:2] == ":": - # nt root (something like c:/) - return path_[0] + ":/" - # More cases may be required here - return path_ - - @classmethod - def _strip_protocol(cls, path): - path = stringify_path(path) - if path.startswith("file://"): - path = path[7:] - elif path.startswith("file:"): - path = path[5:] - elif path.startswith("local://"): - path = path[8:] - elif path.startswith("local:"): - path = path[6:] - - path = make_path_posix(path) - if os.sep != "/": - # This code-path is a stripped down version of - # > drive, path = ntpath.splitdrive(path) - if path[1:2] == ":": - # Absolute drive-letter path, e.g. X:\Windows - # Relative path with drive, e.g. X:Windows - drive, path = path[:2], path[2:] - elif path[:2] == "//": - # UNC drives, e.g. \\server\share or \\?\UNC\server\share - # Device drives, e.g. \\.\device or \\?\device - if (index1 := path.find("/", 2)) == -1 or ( - index2 := path.find("/", index1 + 1) - ) == -1: - drive, path = path, "" - else: - drive, path = path[:index2], path[index2:] - else: - # Relative path, e.g. Windows - drive = "" - - path = path.rstrip("/") or cls.root_marker - return drive + path - - else: - return path.rstrip("/") or cls.root_marker - - def _isfilestore(self): - # Inheriting from DaskFileSystem makes this False (S3, etc. were) - # the original motivation. But we are a posix-like file system. - # See https://github.com/dask/dask/issues/5526 - return True - - def chmod(self, path, mode): - path = stringify_path(path) - return os.chmod(path, mode) - - -def make_path_posix(path): - """Make path generic and absolute for current OS""" - if not isinstance(path, str): - if isinstance(path, (list, set, tuple)): - return type(path)(make_path_posix(p) for p in path) - else: - path = stringify_path(path) - if not isinstance(path, str): - raise TypeError(f"could not convert {path!r} to string") - if os.sep == "/": - # Native posix - if path.startswith("/"): - # most common fast case for posix - return path - elif path.startswith("~"): - return osp.expanduser(path) - elif path.startswith("./"): - path = path[2:] - elif path == ".": - path = "" - return f"{os.getcwd()}/{path}" - else: - # NT handling - if path[0:1] == "/" and path[2:3] == ":": - # path is like "/c:/local/path" - path = path[1:] - if path[1:2] == ":": - # windows full path like "C:\\local\\path" - if len(path) <= 3: - # nt root (something like c:/) - return path[0] + ":/" - path = path.replace("\\", "/") - return path - elif path[0:1] == "~": - return make_path_posix(osp.expanduser(path)) - elif path.startswith(("\\\\", "//")): - # windows UNC/DFS-style paths - return "//" + path[2:].replace("\\", "/") - elif path.startswith(("\\", "/")): - # windows relative path with root - path = path.replace("\\", "/") - return f"{osp.splitdrive(os.getcwd())[0]}{path}" - else: - path = path.replace("\\", "/") - if path.startswith("./"): - path = path[2:] - elif path == ".": - path = "" - return f"{make_path_posix(os.getcwd())}/{path}" - - -def trailing_sep(path): - """Return True if the path ends with a path separator. - - A forward slash is always considered a path separator, even on Operating - Systems that normally use a backslash. - """ - # TODO: if all incoming paths were posix-compliant then separator would - # always be a forward slash, simplifying this function. - # See https://github.com/fsspec/filesystem_spec/pull/1250 - return path.endswith(os.sep) or (os.altsep is not None and path.endswith(os.altsep)) - - -@lru_cache(maxsize=1) -def get_umask(mask: int = 0o666) -> int: - """Get the current umask. - - Follows https://stackoverflow.com/a/44130549 to get the umask. - Temporarily sets the umask to the given value, and then resets it to the - original value. - """ - value = os.umask(mask) - os.umask(value) - return value - - -class LocalFileOpener(io.IOBase): - def __init__( - self, path, mode, autocommit=True, fs=None, compression=None, **kwargs - ): - logger.debug("open file: %s", path) - self.path = path - self.mode = mode - self.fs = fs - self.f = None - self.autocommit = autocommit - self.compression = get_compression(path, compression) - self.blocksize = io.DEFAULT_BUFFER_SIZE - self._open() - - def _open(self): - if self.f is None or self.f.closed: - if self.autocommit or "w" not in self.mode: - self.f = open(self.path, mode=self.mode) - if self.compression: - compress = compr[self.compression] - self.f = compress(self.f, mode=self.mode) - else: - # TODO: check if path is writable? - i, name = tempfile.mkstemp() - os.close(i) # we want normal open and normal buffered file - self.temp = name - self.f = open(name, mode=self.mode) - if "w" not in self.mode: - self.size = self.f.seek(0, 2) - self.f.seek(0) - self.f.size = self.size - - def _fetch_range(self, start, end): - # probably only used by cached FS - if "r" not in self.mode: - raise ValueError - self._open() - self.f.seek(start) - return self.f.read(end - start) - - def __setstate__(self, state): - self.f = None - loc = state.pop("loc", None) - self.__dict__.update(state) - if "r" in state["mode"]: - self.f = None - self._open() - self.f.seek(loc) - - def __getstate__(self): - d = self.__dict__.copy() - d.pop("f") - if "r" in self.mode: - d["loc"] = self.f.tell() - else: - if not self.f.closed: - raise ValueError("Cannot serialise open write-mode local file") - return d - - def commit(self): - if self.autocommit: - raise RuntimeError("Can only commit if not already set to autocommit") - try: - shutil.move(self.temp, self.path) - except PermissionError as e: - # shutil.move raises PermissionError if os.rename - # and the default copy2 fallback with shutil.copystats fail. - # The file should be there nonetheless, but without copied permissions. - # If it doesn't exist, there was no permission to create the file. - if not os.path.exists(self.path): - raise e - else: - # If PermissionError is not raised, permissions can be set. - try: - mask = 0o666 - os.chmod(self.path, mask & ~get_umask(mask)) - except RuntimeError: - pass - - def discard(self): - if self.autocommit: - raise RuntimeError("Cannot discard if set to autocommit") - os.remove(self.temp) - - def readable(self) -> bool: - return True - - def writable(self) -> bool: - return "r" not in self.mode - - def read(self, *args, **kwargs): - return self.f.read(*args, **kwargs) - - def write(self, *args, **kwargs): - return self.f.write(*args, **kwargs) - - def tell(self, *args, **kwargs): - return self.f.tell(*args, **kwargs) - - def seek(self, *args, **kwargs): - return self.f.seek(*args, **kwargs) - - def seekable(self, *args, **kwargs): - return self.f.seekable(*args, **kwargs) - - def readline(self, *args, **kwargs): - return self.f.readline(*args, **kwargs) - - def readlines(self, *args, **kwargs): - return self.f.readlines(*args, **kwargs) - - def close(self): - return self.f.close() - - def truncate(self, size=None) -> int: - return self.f.truncate(size) - - @property - def closed(self): - return self.f.closed - - def fileno(self): - return self.raw.fileno() - - def flush(self) -> None: - self.f.flush() - - def __iter__(self): - return self.f.__iter__() - - def __getattr__(self, item): - return getattr(self.f, item) - - def __enter__(self): - self._incontext = True - return self - - def __exit__(self, exc_type, exc_value, traceback): - self._incontext = False - self.f.__exit__(exc_type, exc_value, traceback) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/memory.py b/venv/lib/python3.10/site-packages/fsspec/implementations/memory.py deleted file mode 100644 index f6b67bbc84e7aa625eee5609c20f6a893ddd349e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/memory.py +++ /dev/null @@ -1,311 +0,0 @@ -from __future__ import annotations - -import logging -from datetime import datetime, timezone -from errno import ENOTEMPTY -from io import BytesIO -from pathlib import PurePath, PureWindowsPath -from typing import Any, ClassVar - -from fsspec import AbstractFileSystem -from fsspec.implementations.local import LocalFileSystem -from fsspec.utils import stringify_path - -logger = logging.getLogger("fsspec.memoryfs") - - -class MemoryFileSystem(AbstractFileSystem): - """A filesystem based on a dict of BytesIO objects - - This is a global filesystem so instances of this class all point to the same - in memory filesystem. - """ - - store: ClassVar[dict[str, Any]] = {} # global, do not overwrite! - pseudo_dirs = [""] # global, do not overwrite! - protocol = "memory" - root_marker = "/" - - @classmethod - def _strip_protocol(cls, path): - if isinstance(path, PurePath): - if isinstance(path, PureWindowsPath): - return LocalFileSystem._strip_protocol(path) - else: - path = stringify_path(path) - - path = path.removeprefix("memory://") - if "::" in path or "://" in path: - return path.rstrip("/") - path = path.lstrip("/").rstrip("/") - return "/" + path if path else "" - - def ls(self, path, detail=True, **kwargs): - path = self._strip_protocol(path) - if path in self.store: - # there is a key with this exact name - if not detail: - return [path] - return [ - { - "name": path, - "size": self.store[path].size, - "type": "file", - "created": self.store[path].created.timestamp(), - } - ] - paths = set() - starter = path + "/" - out = [] - for p2 in tuple(self.store): - if p2.startswith(starter): - if "/" not in p2[len(starter) :]: - # exact child - out.append( - { - "name": p2, - "size": self.store[p2].size, - "type": "file", - "created": self.store[p2].created.timestamp(), - } - ) - elif len(p2) > len(starter): - # implied child directory - ppath = starter + p2[len(starter) :].split("/", 1)[0] - if ppath not in paths: - out = out or [] - out.append( - { - "name": ppath, - "size": 0, - "type": "directory", - } - ) - paths.add(ppath) - for p2 in self.pseudo_dirs: - if p2.startswith(starter): - if "/" not in p2[len(starter) :]: - # exact child pdir - if p2 not in paths: - out.append({"name": p2, "size": 0, "type": "directory"}) - paths.add(p2) - else: - # directory implied by deeper pdir - ppath = starter + p2[len(starter) :].split("/", 1)[0] - if ppath not in paths: - out.append({"name": ppath, "size": 0, "type": "directory"}) - paths.add(ppath) - if not out: - if path in self.pseudo_dirs: - # empty dir - return [] - raise FileNotFoundError(path) - if detail: - return out - return sorted([f["name"] for f in out]) - - def mkdir(self, path, create_parents=True, **kwargs): - path = self._strip_protocol(path) - if path in self.store or path in self.pseudo_dirs: - raise FileExistsError(path) - if self._parent(path).strip("/") and self.isfile(self._parent(path)): - raise NotADirectoryError(self._parent(path)) - if create_parents and self._parent(path).strip("/"): - try: - self.mkdir(self._parent(path), create_parents, **kwargs) - except FileExistsError: - pass - if path and path not in self.pseudo_dirs: - self.pseudo_dirs.append(path) - - def makedirs(self, path, exist_ok=False): - try: - self.mkdir(path, create_parents=True) - except FileExistsError: - if not exist_ok: - raise - - def pipe_file(self, path, value, mode="overwrite", **kwargs): - """Set the bytes of given file - - Avoids copies of the data if possible - """ - mode = "xb" if mode == "create" else "wb" - self.open(path, mode=mode, data=value) - - def rmdir(self, path): - path = self._strip_protocol(path) - if path == "": - # silently avoid deleting FS root - return - if path in self.pseudo_dirs: - if not self.ls(path): - self.pseudo_dirs.remove(path) - else: - raise OSError(ENOTEMPTY, "Directory not empty", path) - else: - raise FileNotFoundError(path) - - def info(self, path, **kwargs): - logger.debug("info: %s", path) - path = self._strip_protocol(path) - if path in self.pseudo_dirs or any( - p.startswith(path + "/") for p in list(self.store) + self.pseudo_dirs - ): - return { - "name": path, - "size": 0, - "type": "directory", - } - elif path in self.store: - filelike = self.store[path] - return { - "name": path, - "size": filelike.size, - "type": "file", - "created": getattr(filelike, "created", None), - } - else: - raise FileNotFoundError(path) - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - **kwargs, - ): - path = self._strip_protocol(path) - if "x" in mode and self.exists(path): - raise FileExistsError - if path in self.pseudo_dirs: - raise IsADirectoryError(path) - parent = path - while len(parent) > 1: - parent = self._parent(parent) - if self.isfile(parent): - raise FileExistsError(parent) - if mode in ["rb", "ab", "r+b", "a+b"]: - if path in self.store: - f = self.store[path] - if "a" in mode: - # position at the end of file - f.seek(0, 2) - else: - # position at the beginning of file - f.seek(0) - return f - else: - raise FileNotFoundError(path) - elif mode in {"wb", "w+b", "xb", "x+b"}: - if "x" in mode and self.exists(path): - raise FileExistsError - m = MemoryFile(self, path, kwargs.get("data")) - if not self._intrans: - m.commit() - return m - else: - name = self.__class__.__name__ - raise ValueError(f"unsupported file mode for {name}: {mode!r}") - - def cp_file(self, path1, path2, **kwargs): - path1 = self._strip_protocol(path1) - path2 = self._strip_protocol(path2) - if self.isfile(path1): - self.store[path2] = MemoryFile( - self, path2, self.store[path1].getvalue() - ) # implicit copy - elif self.isdir(path1): - if path2 not in self.pseudo_dirs: - self.pseudo_dirs.append(path2) - else: - raise FileNotFoundError(path1) - - def cat_file(self, path, start=None, end=None, **kwargs): - logger.debug("cat: %s", path) - path = self._strip_protocol(path) - try: - return bytes(self.store[path].getbuffer()[start:end]) - except KeyError as e: - raise FileNotFoundError(path) from e - - def _rm(self, path): - path = self._strip_protocol(path) - try: - del self.store[path] - except KeyError as e: - raise FileNotFoundError(path) from e - - def modified(self, path): - path = self._strip_protocol(path) - try: - return self.store[path].modified - except KeyError as e: - raise FileNotFoundError(path) from e - - def created(self, path): - path = self._strip_protocol(path) - try: - return self.store[path].created - except KeyError as e: - raise FileNotFoundError(path) from e - - def isfile(self, path): - path = self._strip_protocol(path) - return path in self.store - - def rm(self, path, recursive=False, maxdepth=None): - if isinstance(path, str): - path = self._strip_protocol(path) - else: - path = [self._strip_protocol(p) for p in path] - paths = self.expand_path(path, recursive=recursive, maxdepth=maxdepth) - for p in reversed(paths): - if self.isfile(p): - self.rm_file(p) - # If the expanded path doesn't exist, it is only because the expanded - # path was a directory that does not exist in self.pseudo_dirs. This - # is possible if you directly create files without making the - # directories first. - elif not self.exists(p): - continue - else: - self.rmdir(p) - - -class MemoryFile(BytesIO): - """A BytesIO which can't close and works as a context manager - - Can initialise with data. Each path should only be active once at any moment. - - No need to provide fs, path if auto-committing (default) - """ - - def __init__(self, fs=None, path=None, data=None): - logger.debug("open file %s", path) - self.fs = fs - self.path = path - self.created = datetime.now(tz=timezone.utc) - self.modified = datetime.now(tz=timezone.utc) - if data: - super().__init__(data) - self.seek(0) - - @property - def size(self): - return self.getbuffer().nbytes - - def __enter__(self): - return self - - def close(self): - pass - - def discard(self): - pass - - def commit(self): - self.fs.store[self.path] = self - self.modified = datetime.now(tz=timezone.utc) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/reference.py b/venv/lib/python3.10/site-packages/fsspec/implementations/reference.py deleted file mode 100644 index 54e81224bd2c6aa182319c189aae26090f92572b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/reference.py +++ /dev/null @@ -1,1311 +0,0 @@ -import base64 -import collections -import io -import itertools -import logging -import math -import os -from functools import lru_cache -from itertools import chain -from typing import TYPE_CHECKING, Literal - -import fsspec.core -from fsspec.spec import AbstractBufferedFile - -try: - import ujson as json -except ImportError: - if not TYPE_CHECKING: - import json - -from fsspec.asyn import AsyncFileSystem -from fsspec.callbacks import DEFAULT_CALLBACK -from fsspec.core import filesystem, open, split_protocol -from fsspec.implementations.asyn_wrapper import AsyncFileSystemWrapper -from fsspec.utils import ( - isfilelike, - merge_offset_ranges, - other_paths, -) - -logger = logging.getLogger("fsspec.reference") - - -class ReferenceNotReachable(RuntimeError): - def __init__(self, reference, target, *args): - super().__init__(*args) - self.reference = reference - self.target = target - - def __str__(self): - return f'Reference "{self.reference}" failed to fetch target {self.target}' - - -def _first(d): - return next(iter(d.values())) - - -def _prot_in_references(path, references): - ref = references.get(path) - if isinstance(ref, (list, tuple)) and isinstance(ref[0], str): - return split_protocol(ref[0])[0] if ref[0] else ref[0] - - -def _protocol_groups(paths, references): - if isinstance(paths, str): - return {_prot_in_references(paths, references): [paths]} - out = {} - for path in paths: - protocol = _prot_in_references(path, references) - out.setdefault(protocol, []).append(path) - return out - - -class RefsValuesView(collections.abc.ValuesView): - def __iter__(self): - for val in self._mapping.zmetadata.values(): - yield json.dumps(val).encode() - yield from self._mapping._items.values() - for field in self._mapping.listdir(): - chunk_sizes = self._mapping._get_chunk_sizes(field) - if len(chunk_sizes) == 0: - yield self._mapping[field + "/0"] - continue - yield from self._mapping._generate_all_records(field) - - -class RefsItemsView(collections.abc.ItemsView): - def __iter__(self): - return zip(self._mapping.keys(), self._mapping.values()) - - -def ravel_multi_index(idx, sizes): - val = 0 - mult = 1 - for i, s in zip(idx[::-1], sizes[::-1]): - val += i * mult - mult *= s - return val - - -class LazyReferenceMapper(collections.abc.MutableMapping): - """This interface can be used to read/write references from Parquet stores. - It is not intended for other types of references. - It can be used with Kerchunk's MultiZarrToZarr method to combine - references into a parquet store. - Examples of this use-case can be found here: - https://fsspec.github.io/kerchunk/advanced.html?highlight=parquet#parquet-storage""" - - # import is class level to prevent numpy dep requirement for fsspec - @property - def np(self): - import numpy as np - - return np - - @property - def pd(self): - import pandas as pd - - return pd - - def __init__( - self, - root, - fs=None, - out_root=None, - cache_size=128, - categorical_threshold=10, - engine: Literal["fastparquet", "pyarrow"] = "fastparquet", - ): - """ - - This instance will be writable, storing changes in memory until full partitions - are accumulated or .flush() is called. - - To create an empty lazy store, use .create() - - Parameters - ---------- - root : str - Root of parquet store - fs : fsspec.AbstractFileSystem - fsspec filesystem object, default is local filesystem. - cache_size : int, default=128 - Maximum size of LRU cache, where cache_size*record_size denotes - the total number of references that can be loaded in memory at once. - categorical_threshold : int - Encode urls as pandas.Categorical to reduce memory footprint if the ratio - of the number of unique urls to total number of refs for each variable - is greater than or equal to this number. (default 10) - engine: Literal["fastparquet","pyarrow"] - Engine choice for reading parquet files. (default is "fastparquet") - """ - - self.root = root - self.chunk_sizes = {} - self.cat_thresh = categorical_threshold - self.engine = engine - self.cache_size = cache_size - self.url = self.root + "/{field}/refs.{record}.parq" - # TODO: derive fs from `root` - self.fs = fsspec.filesystem("file") if fs is None else fs - self.out_root = self.fs.unstrip_protocol(out_root or self.root) - - from importlib.util import find_spec - - if self.engine == "pyarrow" and find_spec("pyarrow") is None: - raise ImportError("engine choice `pyarrow` is not installed.") - - def __getattr__(self, item): - if item in ("_items", "record_size", "zmetadata"): - self.setup() - # avoid possible recursion if setup fails somehow - return self.__dict__[item] - raise AttributeError(item) - - def setup(self): - self._items = {} - self._items[".zmetadata"] = self.fs.cat_file( - "/".join([self.root, ".zmetadata"]) - ) - met = json.loads(self._items[".zmetadata"]) - self.record_size = met["record_size"] - self.zmetadata = met["metadata"] - - # Define function to open and decompress refs - @lru_cache(maxsize=self.cache_size) - def open_refs(field, record): - """cached parquet file loader""" - path = self.url.format(field=field, record=record) - data = io.BytesIO(self.fs.cat_file(path)) - try: - df = self.pd.read_parquet(data, engine=self.engine) - refs = {c: df[c].to_numpy() for c in df.columns} - except OSError: - refs = None - return refs - - self.open_refs = open_refs - - @staticmethod - def create(root, storage_options=None, fs=None, record_size=10000, **kwargs): - """Make empty parquet reference set - - First deletes the contents of the given directory, if it exists. - - Parameters - ---------- - root: str - Directory to contain the output; will be created - storage_options: dict | None - For making the filesystem to use for writing is fs is None - fs: FileSystem | None - Filesystem for writing - record_size: int - Number of references per parquet file - kwargs: passed to __init__ - - Returns - ------- - LazyReferenceMapper instance - """ - met = {"metadata": {}, "record_size": record_size} - if fs is None: - fs, root = fsspec.core.url_to_fs(root, **(storage_options or {})) - if fs.exists(root): - fs.rm(root, recursive=True) - fs.makedirs(root, exist_ok=True) - fs.pipe("/".join([root, ".zmetadata"]), json.dumps(met).encode()) - return LazyReferenceMapper(root, fs, **kwargs) - - @lru_cache - def listdir(self): - """List top-level directories""" - dirs = (p.rsplit("/", 1)[0] for p in self.zmetadata if not p.startswith(".z")) - return set(dirs) - - def ls(self, path="", detail=True): - """Shortcut file listings""" - path = path.rstrip("/") - pathdash = path + "/" if path else "" - dirnames = self.listdir() - dirs = [ - d - for d in dirnames - if d.startswith(pathdash) and "/" not in d.lstrip(pathdash) - ] - if dirs: - others = { - f - for f in chain( - [".zmetadata"], - (name for name in self.zmetadata), - (name for name in self._items), - ) - if f.startswith(pathdash) and "/" not in f.lstrip(pathdash) - } - if detail is False: - others.update(dirs) - return sorted(others) - dirinfo = [{"name": name, "type": "directory", "size": 0} for name in dirs] - fileinfo = [ - { - "name": name, - "type": "file", - "size": len( - json.dumps(self.zmetadata[name]) - if name in self.zmetadata - else self._items[name] - ), - } - for name in others - ] - return sorted(dirinfo + fileinfo, key=lambda s: s["name"]) - field = path - others = set( - [name for name in self.zmetadata if name.startswith(f"{path}/")] - + [name for name in self._items if name.startswith(f"{path}/")] - ) - fileinfo = [ - { - "name": name, - "type": "file", - "size": len( - json.dumps(self.zmetadata[name]) - if name in self.zmetadata - else self._items[name] - ), - } - for name in others - ] - keys = self._keys_in_field(field) - - if detail is False: - return list(others) + list(keys) - recs = self._generate_all_records(field) - recinfo = [ - {"name": name, "type": "file", "size": rec[-1]} - for name, rec in zip(keys, recs) - if rec[0] # filters out path==None, deleted/missing - ] - return fileinfo + recinfo - - def _load_one_key(self, key): - """Get the reference for one key - - Returns bytes, one-element list or three-element list. - """ - if key in self._items: - return self._items[key] - elif key in self.zmetadata: - return json.dumps(self.zmetadata[key]).encode() - elif "/" not in key or self._is_meta(key): - raise KeyError(key) - field, _ = key.rsplit("/", 1) - record, ri, chunk_size = self._key_to_record(key) - maybe = self._items.get((field, record), {}).get(ri, False) - if maybe is None: - # explicitly deleted - raise KeyError - elif maybe: - return maybe - elif chunk_size == 0: - return b"" - - # Chunk keys can be loaded from row group and cached in LRU cache - try: - refs = self.open_refs(field, record) - except (ValueError, TypeError, FileNotFoundError) as exc: - raise KeyError(key) from exc - columns = ["path", "offset", "size", "raw"] - selection = [refs[c][ri] if c in refs else None for c in columns] - raw = selection[-1] - if raw is not None: - return raw - if selection[0] is None: - raise KeyError("This reference does not exist or has been deleted") - if selection[1:3] == [0, 0]: - # URL only - return selection[:1] - # URL, offset, size - return selection[:3] - - @lru_cache(4096) - def _key_to_record(self, key): - """Details needed to construct a reference for one key""" - field, chunk = key.rsplit("/", 1) - chunk_sizes = self._get_chunk_sizes(field) - if len(chunk_sizes) == 0: - return 0, 0, 0 - chunk_idx = [int(c) for c in chunk.split(".")] - chunk_number = ravel_multi_index(chunk_idx, chunk_sizes) - record = chunk_number // self.record_size - ri = chunk_number % self.record_size - return record, ri, len(chunk_sizes) - - def _get_chunk_sizes(self, field): - """The number of chunks along each axis for a given field""" - if field not in self.chunk_sizes: - zarray = self.zmetadata[f"{field}/.zarray"] - size_ratio = [ - math.ceil(s / c) for s, c in zip(zarray["shape"], zarray["chunks"]) - ] - self.chunk_sizes[field] = size_ratio or [1] - return self.chunk_sizes[field] - - def _generate_record(self, field, record): - """The references for a given parquet file of a given field""" - refs = self.open_refs(field, record) - it = iter(zip(*refs.values())) - if len(refs) == 3: - # All urls - return (list(t) for t in it) - elif len(refs) == 1: - # All raws - return refs["raw"] - else: - # Mix of urls and raws - return (list(t[:3]) if not t[3] else t[3] for t in it) - - def _generate_all_records(self, field): - """Load all the references within a field by iterating over the parquet files""" - nrec = 1 - for ch in self._get_chunk_sizes(field): - nrec *= ch - nrec = math.ceil(nrec / self.record_size) - for record in range(nrec): - yield from self._generate_record(field, record) - - def values(self): - return RefsValuesView(self) - - def items(self): - return RefsItemsView(self) - - def __hash__(self): - return id(self) - - def __getitem__(self, key): - return self._load_one_key(key) - - def __setitem__(self, key, value): - if "/" in key and not self._is_meta(key): - field, chunk = key.rsplit("/", 1) - record, i, _ = self._key_to_record(key) - subdict = self._items.setdefault((field, record), {}) - subdict[i] = value - if len(subdict) == self.record_size: - self.write(field, record) - else: - # metadata or top-level - if hasattr(value, "to_bytes"): - val = value.to_bytes().decode() - elif isinstance(value, bytes): - val = value.decode() - else: - val = value - self._items[key] = val - new_value = json.loads(val) - self.zmetadata[key] = {**self.zmetadata.get(key, {}), **new_value} - - @staticmethod - def _is_meta(key): - return key.startswith(".z") or "/.z" in key - - def __delitem__(self, key): - if key in self._items: - del self._items[key] - elif key in self.zmetadata: - del self.zmetadata[key] - else: - if "/" in key and not self._is_meta(key): - field, _ = key.rsplit("/", 1) - record, i, _ = self._key_to_record(key) - subdict = self._items.setdefault((field, record), {}) - subdict[i] = None - if len(subdict) == self.record_size: - self.write(field, record) - else: - # metadata or top-level - self._items[key] = None - - def write(self, field, record, base_url=None, storage_options=None): - # extra requirements if writing - import kerchunk.df - import numpy as np - import pandas as pd - - partition = self._items[(field, record)] - original = False - if len(partition) < self.record_size: - try: - original = self.open_refs(field, record) - except OSError: - pass - - if original: - paths = original["path"] - offsets = original["offset"] - sizes = original["size"] - raws = original["raw"] - else: - paths = np.full(self.record_size, np.nan, dtype="O") - offsets = np.zeros(self.record_size, dtype="int64") - sizes = np.zeros(self.record_size, dtype="int64") - raws = np.full(self.record_size, np.nan, dtype="O") - for j, data in partition.items(): - if isinstance(data, list): - if ( - str(paths.dtype) == "category" - and data[0] not in paths.dtype.categories - ): - paths = paths.add_categories(data[0]) - paths[j] = data[0] - if len(data) > 1: - offsets[j] = data[1] - sizes[j] = data[2] - elif data is None: - # delete - paths[j] = None - offsets[j] = 0 - sizes[j] = 0 - raws[j] = None - else: - # this is the only call into kerchunk, could remove - raws[j] = kerchunk.df._proc_raw(data) - # TODO: only save needed columns - df = pd.DataFrame( - { - "path": paths, - "offset": offsets, - "size": sizes, - "raw": raws, - }, - copy=False, - ) - if df.path.count() / (df.path.nunique() or 1) > self.cat_thresh: - df["path"] = df["path"].astype("category") - object_encoding = {"raw": "bytes", "path": "utf8"} - has_nulls = ["path", "raw"] - - fn = f"{base_url or self.out_root}/{field}/refs.{record}.parq" - self.fs.mkdirs(f"{base_url or self.out_root}/{field}", exist_ok=True) - - if self.engine == "pyarrow": - df_backend_kwargs = {"write_statistics": False} - elif self.engine == "fastparquet": - df_backend_kwargs = { - "stats": False, - "object_encoding": object_encoding, - "has_nulls": has_nulls, - } - else: - raise NotImplementedError(f"{self.engine} not supported") - df.to_parquet( - fn, - engine=self.engine, - storage_options=storage_options - or getattr(self.fs, "storage_options", None), - compression="zstd", - index=False, - **df_backend_kwargs, - ) - - partition.clear() - self._items.pop((field, record)) - - def flush(self, base_url=None, storage_options=None): - """Output any modified or deleted keys - - Parameters - ---------- - base_url: str - Location of the output - """ - - # write what we have so far and clear sub chunks - for thing in list(self._items): - if isinstance(thing, tuple): - field, record = thing - self.write( - field, - record, - base_url=base_url, - storage_options=storage_options, - ) - - # gather .zmetadata from self._items and write that too - for k in list(self._items): - if k != ".zmetadata" and ".z" in k: - self.zmetadata[k] = json.loads(self._items.pop(k)) - met = {"metadata": self.zmetadata, "record_size": self.record_size} - self._items.clear() - self._items[".zmetadata"] = json.dumps(met).encode() - self.fs.pipe( - "/".join([base_url or self.out_root, ".zmetadata"]), - self._items[".zmetadata"], - ) - - # TODO: only clear those that we wrote to? - self.open_refs.cache_clear() - - def __len__(self): - # Caveat: This counts expected references, not actual - but is fast - count = 0 - for field in self.listdir(): - if field.startswith("."): - count += 1 - else: - count += math.prod(self._get_chunk_sizes(field)) - count += len(self.zmetadata) # all metadata keys - # any other files not in reference partitions - count += sum(1 for _ in self._items if not isinstance(_, tuple)) - return count - - def __iter__(self): - # Caveat: returns only existing keys, so the number of these does not - # match len(self) - metas = set(self.zmetadata) - metas.update(self._items) - for bit in metas: - if isinstance(bit, str): - yield bit - for field in self.listdir(): - for k in self._keys_in_field(field): - if k in self: - yield k - - def __contains__(self, item): - try: - self._load_one_key(item) - return True - except KeyError: - return False - - def _keys_in_field(self, field): - """List key names in given field - - Produces strings like "field/x.y" appropriate from the chunking of the array - """ - chunk_sizes = self._get_chunk_sizes(field) - if len(chunk_sizes) == 0: - yield field + "/0" - return - inds = itertools.product(*(range(i) for i in chunk_sizes)) - for ind in inds: - yield field + "/" + ".".join([str(c) for c in ind]) - - -class ReferenceFileSystem(AsyncFileSystem): - """View byte ranges of some other file as a file system - Initial version: single file system target, which must support - async, and must allow start and end args in _cat_file. Later versions - may allow multiple arbitrary URLs for the targets. - This FileSystem is read-only. It is designed to be used with async - targets (for now). We do not get original file details from the target FS. - Configuration is by passing a dict of references at init, or a URL to - a JSON file containing the same; this dict - can also contain concrete data for some set of paths. - Reference dict format: - {path0: bytes_data, path1: (target_url, offset, size)} - https://github.com/fsspec/kerchunk/blob/main/README.md - """ - - protocol = "reference" - cachable = False - - def __init__( - self, - fo, - target=None, - ref_storage_args=None, - target_protocol=None, - target_options=None, - remote_protocol=None, - remote_options=None, - fs=None, - template_overrides=None, - simple_templates=True, - max_gap=64_000, - max_block=256_000_000, - cache_size=128, - **kwargs, - ): - """ - Parameters - ---------- - fo : dict or str - The set of references to use for this instance, with a structure as above. - If str referencing a JSON file, will use fsspec.open, in conjunction - with target_options and target_protocol to open and parse JSON at this - location. If a directory, then assume references are a set of parquet - files to be loaded lazily. - target : str - For any references having target_url as None, this is the default file - target to use - ref_storage_args : dict - If references is a str, use these kwargs for loading the JSON file. - Deprecated: use target_options instead. - target_protocol : str - Used for loading the reference file, if it is a path. If None, protocol - will be derived from the given path - target_options : dict - Extra FS options for loading the reference file ``fo``, if given as a path - remote_protocol : str - The protocol of the filesystem on which the references will be evaluated - (unless fs is provided). If not given, will be derived from the first - URL that has a protocol in the templates or in the references, in that - order. - remote_options : dict - kwargs to go with remote_protocol - fs : AbstractFileSystem | dict(str, (AbstractFileSystem | dict)) - Directly provide a file system(s): - - a single filesystem instance - - a dict of protocol:filesystem, where each value is either a filesystem - instance, or a dict of kwargs that can be used to create in - instance for the given protocol - - If this is given, remote_options and remote_protocol are ignored. - template_overrides : dict - Swap out any templates in the references file with these - useful for - testing. - simple_templates: bool - Whether templates can be processed with simple replace (True) or if - jinja is needed (False, much slower). All reference sets produced by - ``kerchunk`` are simple in this sense, but the spec allows for complex. - max_gap, max_block: int - For merging multiple concurrent requests to the same remote file. - Neighboring byte ranges will only be merged when their - inter-range gap is <= ``max_gap``. Default is 64KB. Set to 0 - to only merge when it requires no extra bytes. Pass a negative - number to disable merging, appropriate for local target files. - Neighboring byte ranges will only be merged when the size of - the aggregated range is <= ``max_block``. Default is 256MB. - cache_size : int - Maximum size of LRU cache, where cache_size*record_size denotes - the total number of references that can be loaded in memory at once. - Only used for lazily loaded references. - kwargs : passed to parent class - """ - super().__init__(**kwargs) - self.target = target - self.template_overrides = template_overrides - self.simple_templates = simple_templates - self.templates = {} - self.fss = {} - self._dircache = {} - self.max_gap = max_gap - self.max_block = max_block - if isinstance(fo, str): - dic = dict( - **(ref_storage_args or target_options or {}), protocol=target_protocol - ) - ref_fs, fo2 = fsspec.core.url_to_fs(fo, **dic) - if ".json" not in fo2 and ( - fo.endswith(("parq", "parquet", "/")) or ref_fs.isdir(fo2) - ): - # Lazy parquet refs - logger.info("Open lazy reference dict from URL %s", fo) - self.references = LazyReferenceMapper( - fo2, - fs=ref_fs, - cache_size=cache_size, - ) - else: - # text JSON - with fsspec.open(fo, "rb", **dic) as f: - logger.info("Read reference from URL %s", fo) - text = json.load(f) - self._process_references(text, template_overrides) - else: - # dictionaries - self._process_references(fo, template_overrides) - if isinstance(fs, dict): - self.fss = { - k: ( - fsspec.filesystem(k.split(":", 1)[0], **opts) - if isinstance(opts, dict) - else opts - ) - for k, opts in fs.items() - } - if None not in self.fss: - self.fss[None] = filesystem("file") - return - if fs is not None: - # single remote FS - remote_protocol = ( - fs.protocol[0] if isinstance(fs.protocol, tuple) else fs.protocol - ) - self.fss[remote_protocol] = fs - - if remote_protocol is None: - # get single protocol from any templates - for ref in self.templates.values(): - if callable(ref): - ref = ref() - protocol, _ = fsspec.core.split_protocol(ref) - if protocol and protocol not in self.fss: - fs = filesystem(protocol, **(remote_options or {})) - self.fss[protocol] = fs - if remote_protocol is None: - # get single protocol from references - # TODO: warning here, since this can be very expensive? - for ref in self.references.values(): - if callable(ref): - ref = ref() - if isinstance(ref, list) and ref[0]: - protocol, _ = fsspec.core.split_protocol(ref[0]) - if protocol not in self.fss: - fs = filesystem(protocol, **(remote_options or {})) - self.fss[protocol] = fs - # only use first remote URL - break - - if remote_protocol and remote_protocol not in self.fss: - fs = filesystem(remote_protocol, **(remote_options or {})) - self.fss[remote_protocol] = fs - - self.fss[None] = fs or filesystem("file") # default one - # Wrap any non-async filesystems to ensure async methods are available below - for k, f in self.fss.items(): - if not f.async_impl: - self.fss[k] = AsyncFileSystemWrapper(f, asynchronous=self.asynchronous) - elif self.asynchronous ^ f.asynchronous: - raise ValueError( - "Reference-FS's target filesystem must have same value " - "of asynchronous" - ) - - def _cat_common(self, path, start=None, end=None): - path = self._strip_protocol(path) - logger.debug(f"cat: {path}") - try: - part = self.references[path] - except KeyError as exc: - raise FileNotFoundError(path) from exc - if isinstance(part, str): - part = part.encode() - if hasattr(part, "to_bytes"): - part = part.to_bytes() - if isinstance(part, bytes): - logger.debug(f"Reference: {path}, type bytes") - if part.startswith(b"base64:"): - part = base64.b64decode(part[7:]) - return part, None, None - - if len(part) == 1: - logger.debug(f"Reference: {path}, whole file => {part}") - url = part[0] - start1, end1 = start, end - else: - url, start0, size = part - logger.debug(f"Reference: {path} => {url}, offset {start0}, size {size}") - end0 = start0 + size - - if start is not None: - if start >= 0: - start1 = start0 + start - else: - start1 = end0 + start - else: - start1 = start0 - if end is not None: - if end >= 0: - end1 = start0 + end - else: - end1 = end0 + end - else: - end1 = end0 - if url is None: - url = self.target - return url, start1, end1 - - async def _cat_file(self, path, start=None, end=None, **kwargs): - part_or_url, start0, end0 = self._cat_common(path, start=start, end=end) - if isinstance(part_or_url, bytes): - return part_or_url[start:end] - protocol, _ = split_protocol(part_or_url) - try: - return await self.fss[protocol]._cat_file( - part_or_url, start=start0, end=end0 - ) - except Exception as e: - raise ReferenceNotReachable(path, part_or_url) from e - - def cat_file(self, path, start=None, end=None, **kwargs): - part_or_url, start0, end0 = self._cat_common(path, start=start, end=end) - if isinstance(part_or_url, bytes): - return part_or_url[start:end] - protocol, _ = split_protocol(part_or_url) - try: - return self.fss[protocol].cat_file(part_or_url, start=start0, end=end0) - except Exception as e: - raise ReferenceNotReachable(path, part_or_url) from e - - def pipe_file(self, path, value, **_): - """Temporarily add binary data or reference as a file""" - self.references[path] = value - - async def _get_file(self, rpath, lpath, **kwargs): - if self.isdir(rpath): - return os.makedirs(lpath, exist_ok=True) - data = await self._cat_file(rpath) - with open(lpath, "wb") as f: - f.write(data) - - def get_file(self, rpath, lpath, callback=DEFAULT_CALLBACK, **kwargs): - if self.isdir(rpath): - return os.makedirs(lpath, exist_ok=True) - data = self.cat_file(rpath, **kwargs) - callback.set_size(len(data)) - if isfilelike(lpath): - lpath.write(data) - else: - with open(lpath, "wb") as f: - f.write(data) - callback.absolute_update(len(data)) - - def get(self, rpath, lpath, recursive=False, **kwargs): - if recursive: - # trigger directory build - self.ls("") - rpath = self.expand_path(rpath, recursive=recursive) - fs = fsspec.filesystem("file", auto_mkdir=True) - targets = other_paths(rpath, lpath) - if recursive: - data = self.cat([r for r in rpath if not self.isdir(r)]) - else: - data = self.cat(rpath) - for remote, local in zip(rpath, targets): - if remote in data: - fs.pipe_file(local, data[remote]) - - def cat(self, path, recursive=False, on_error="raise", **kwargs): - if isinstance(path, str) and recursive: - raise NotImplementedError - if isinstance(path, list) and (recursive or any("*" in p for p in path)): - raise NotImplementedError - # TODO: if references is lazy, pre-fetch all paths in batch before access - proto_dict = _protocol_groups(path, self.references) - out = {} - for proto, paths in proto_dict.items(): - fs = self.fss[proto] - urls, starts, ends, valid_paths = [], [], [], [] - for p in paths: - # find references or label not-found. Early exit if any not - # found and on_error is "raise" - try: - u, s, e = self._cat_common(p) - if not isinstance(u, (bytes, str)): - # nan/None from parquet - continue - except FileNotFoundError as err: - if on_error == "raise": - raise - if on_error != "omit": - out[p] = err - else: - urls.append(u) - starts.append(s) - ends.append(e) - valid_paths.append(p) - - # process references into form for merging - urls2 = [] - starts2 = [] - ends2 = [] - paths2 = [] - whole_files = set() - for u, s, e, p in zip(urls, starts, ends, valid_paths): - if isinstance(u, bytes): - # data - out[p] = u - elif s is None: - # whole file - limits are None, None, but no further - # entries take for this file - whole_files.add(u) - urls2.append(u) - starts2.append(s) - ends2.append(e) - paths2.append(p) - for u, s, e, p in zip(urls, starts, ends, valid_paths): - # second run to account for files that are to be loaded whole - if s is not None and u not in whole_files: - urls2.append(u) - starts2.append(s) - ends2.append(e) - paths2.append(p) - - # merge and fetch consolidated ranges - new_paths, new_starts, new_ends = merge_offset_ranges( - list(urls2), - list(starts2), - list(ends2), - sort=True, - max_gap=self.max_gap, - max_block=self.max_block, - ) - bytes_out = fs.cat_ranges(new_paths, new_starts, new_ends) - - # unbundle from merged bytes - simple approach - for u, s, e, p in zip(urls, starts, ends, valid_paths): - if p in out: - continue # was bytes, already handled - for np, ns, ne, b in zip(new_paths, new_starts, new_ends, bytes_out): - if np == u and (ns is None or ne is None): - if isinstance(b, Exception): - out[p] = b - else: - out[p] = b[s:e] - elif np == u and s >= ns and e <= ne: - if isinstance(b, Exception): - out[p] = b - else: - out[p] = b[s - ns : (e - ne) or None] - - for k, v in out.copy().items(): - # these were valid references, but fetch failed, so transform exc - if isinstance(v, Exception) and k in self.references: - ex = out[k] - new_ex = ReferenceNotReachable(k, self.references[k]) - new_ex.__cause__ = ex - if on_error == "raise": - raise new_ex - elif on_error != "omit": - out[k] = new_ex - - if len(out) == 1 and isinstance(path, str) and "*" not in path: - return _first(out) - return out - - def _process_references(self, references, template_overrides=None): - vers = references.get("version", None) - if vers is None: - self._process_references0(references) - elif vers == 1: - self._process_references1(references, template_overrides=template_overrides) - else: - raise ValueError(f"Unknown reference spec version: {vers}") - # TODO: we make dircache by iterating over all entries, but for Spec >= 1, - # can replace with programmatic. Is it even needed for mapper interface? - - def _process_references0(self, references): - """Make reference dict for Spec Version 0""" - if isinstance(references, dict): - # do not do this for lazy/parquet backend, which will not make dicts, - # but must remain writable in the original object - references = { - key: json.dumps(val) if isinstance(val, dict) else val - for key, val in references.items() - } - self.references = references - - def _process_references1(self, references, template_overrides=None): - if not self.simple_templates or self.templates: - import jinja2 - self.references = {} - self._process_templates(references.get("templates", {})) - - @lru_cache(1000) - def _render_jinja(u): - return jinja2.Template(u).render(**self.templates) - - for k, v in references.get("refs", {}).items(): - if isinstance(v, str): - if v.startswith("base64:"): - self.references[k] = base64.b64decode(v[7:]) - self.references[k] = v - elif isinstance(v, dict): - self.references[k] = json.dumps(v) - elif self.templates: - u = v[0] - if "{{" in u: - if self.simple_templates: - u = ( - u.replace("{{", "{") - .replace("}}", "}") - .format(**self.templates) - ) - else: - u = _render_jinja(u) - self.references[k] = [u] if len(v) == 1 else [u, v[1], v[2]] - else: - self.references[k] = v - self.references.update(self._process_gen(references.get("gen", []))) - - def _process_templates(self, tmp): - self.templates = {} - if self.template_overrides is not None: - tmp.update(self.template_overrides) - for k, v in tmp.items(): - if "{{" in v: - import jinja2 - - self.templates[k] = lambda temp=v, **kwargs: jinja2.Template( - temp - ).render(**kwargs) - else: - self.templates[k] = v - - def _process_gen(self, gens): - out = {} - for gen in gens: - dimension = { - k: ( - v - if isinstance(v, list) - else range(v.get("start", 0), v["stop"], v.get("step", 1)) - ) - for k, v in gen["dimensions"].items() - } - products = ( - dict(zip(dimension.keys(), values)) - for values in itertools.product(*dimension.values()) - ) - for pr in products: - import jinja2 - - key = jinja2.Template(gen["key"]).render(**pr, **self.templates) - url = jinja2.Template(gen["url"]).render(**pr, **self.templates) - if ("offset" in gen) and ("length" in gen): - offset = int( - jinja2.Template(gen["offset"]).render(**pr, **self.templates) - ) - length = int( - jinja2.Template(gen["length"]).render(**pr, **self.templates) - ) - out[key] = [url, offset, length] - elif ("offset" in gen) ^ ("length" in gen): - raise ValueError( - "Both 'offset' and 'length' are required for a " - "reference generator entry if either is provided." - ) - else: - out[key] = [url] - return out - - def _dircache_from_items(self): - self.dircache = {"": []} - it = self.references.items() - for path, part in it: - if isinstance(part, (bytes, str)) or hasattr(part, "to_bytes"): - size = len(part) - elif len(part) == 1: - size = None - else: - _, _, size = part - par = path.rsplit("/", 1)[0] if "/" in path else "" - par0 = par - subdirs = [par0] - while par0 and par0 not in self.dircache: - # collect parent directories - par0 = self._parent(par0) - subdirs.append(par0) - - subdirs.reverse() - for parent, child in zip(subdirs, subdirs[1:]): - # register newly discovered directories - assert child not in self.dircache - assert parent in self.dircache - self.dircache[parent].append( - {"name": child, "type": "directory", "size": 0} - ) - self.dircache[child] = [] - - self.dircache[par].append({"name": path, "type": "file", "size": size}) - - def _open(self, path, mode="rb", block_size=None, cache_options=None, **kwargs): - part_or_url, start0, end0 = self._cat_common(path) - # This logic is kept outside `ReferenceFile` to avoid unnecessary redirection. - # That does mean `_cat_common` gets called twice if it eventually reaches `ReferenceFile`. - if isinstance(part_or_url, bytes): - return io.BytesIO(part_or_url[start0:end0]) - - protocol, _ = split_protocol(part_or_url) - if start0 is None and end0 is None: - return self.fss[protocol]._open( - part_or_url, - mode, - block_size=block_size, - cache_options=cache_options, - **kwargs, - ) - - return ReferenceFile( - self, - path, - mode, - block_size=block_size, - cache_options=cache_options, - **kwargs, - ) - - def ls(self, path, detail=True, **kwargs): - logger.debug("list %s", path) - path = self._strip_protocol(path) - if isinstance(self.references, LazyReferenceMapper): - try: - return self.references.ls(path, detail) - except KeyError: - pass - raise FileNotFoundError(f"'{path}' is not a known key") - if not self.dircache: - self._dircache_from_items() - out = self._ls_from_cache(path) - if out is None: - raise FileNotFoundError(path) - if detail: - return out - return [o["name"] for o in out] - - def exists(self, path, **kwargs): # overwrite auto-sync version - return self.isdir(path) or self.isfile(path) - - def isdir(self, path): # overwrite auto-sync version - if self.dircache: - return path in self.dircache - elif isinstance(self.references, LazyReferenceMapper): - return path in self.references.listdir() - else: - # this may be faster than building dircache for single calls, but - # by looping will be slow for many calls; could cache it? - return any(_.startswith(f"{path}/") for _ in self.references) - - def isfile(self, path): # overwrite auto-sync version - return path in self.references - - async def _ls(self, path, detail=True, **kwargs): # calls fast sync code - return self.ls(path, detail, **kwargs) - - def find(self, path, maxdepth=None, withdirs=False, detail=False, **kwargs): - if withdirs: - return super().find( - path, maxdepth=maxdepth, withdirs=withdirs, detail=detail, **kwargs - ) - if path: - path = self._strip_protocol(path) - r = sorted(k for k in self.references if k.startswith(path)) - else: - r = sorted(self.references) - if detail: - if not self.dircache: - self._dircache_from_items() - return {k: self._ls_from_cache(k)[0] for k in r} - else: - return r - - def info(self, path, **kwargs): - out = self.references.get(path) - if out is not None: - if isinstance(out, (str, bytes)): - # decode base64 here - return {"name": path, "type": "file", "size": len(out)} - elif len(out) > 1: - return {"name": path, "type": "file", "size": out[2]} - else: - out0 = [{"name": path, "type": "file", "size": None}] - else: - out = self.ls(path, True) - out0 = [o for o in out if o["name"] == path] - if not out0: - return {"name": path, "type": "directory", "size": 0} - if out0[0]["size"] is None: - # if this is a whole remote file, update size using remote FS - prot, _ = split_protocol(self.references[path][0]) - out0[0]["size"] = self.fss[prot].size(self.references[path][0]) - return out0[0] - - async def _info(self, path, **kwargs): # calls fast sync code - return self.info(path) - - async def _rm_file(self, path, **kwargs): - self.references.pop( - path, None - ) # ignores FileNotFound, just as well for directories - self.dircache.clear() # this is a bit heavy handed - - async def _pipe_file(self, path, data, mode="overwrite", **kwargs): - if mode == "create" and self.exists(path): - raise FileExistsError - # can be str or bytes - self.references[path] = data - self.dircache.clear() # this is a bit heavy handed - - async def _put_file(self, lpath, rpath, mode="overwrite", **kwargs): - # puts binary - if mode == "create" and self.exists(rpath): - raise FileExistsError - with open(lpath, "rb") as f: - self.references[rpath] = f.read() - self.dircache.clear() # this is a bit heavy handed - - def save_json(self, url, **storage_options): - """Write modified references into new location""" - out = {} - for k, v in self.references.items(): - if isinstance(v, bytes): - try: - out[k] = v.decode("ascii") - except UnicodeDecodeError: - out[k] = (b"base64:" + base64.b64encode(v)).decode() - else: - out[k] = v - with fsspec.open(url, "wb", **storage_options) as f: - f.write(json.dumps({"version": 1, "refs": out}).encode()) - - -class ReferenceFile(AbstractBufferedFile): - def __init__( - self, - fs, - path, - mode="rb", - block_size="default", - autocommit=True, - cache_type="readahead", - cache_options=None, - size=None, - **kwargs, - ): - super().__init__( - fs, - path, - mode=mode, - block_size=block_size, - autocommit=autocommit, - size=size, - cache_type=cache_type, - cache_options=cache_options, - **kwargs, - ) - part_or_url, self.start, self.end = self.fs._cat_common(self.path) - protocol, _ = split_protocol(part_or_url) - self.src_fs = self.fs.fss[protocol] - self.src_path = part_or_url - self._f = None - - @property - def f(self): - if self._f is None or self._f.closed: - self._f = self.src_fs._open( - self.src_path, - mode=self.mode, - block_size=self.blocksize, - autocommit=self.autocommit, - cache_type="none", - **self.kwargs, - ) - return self._f - - def close(self): - if self._f is not None: - self._f.close() - return super().close() - - def _fetch_range(self, start, end): - start = start + self.start - end = min(end + self.start, self.end) - self.f.seek(start) - return self.f.read(end - start) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/sftp.py b/venv/lib/python3.10/site-packages/fsspec/implementations/sftp.py deleted file mode 100644 index 6a6db5b569c6f5c4d154372e7fb3c02741388fad..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/sftp.py +++ /dev/null @@ -1,187 +0,0 @@ -import datetime -import logging -import os -import types -import uuid -from stat import S_ISDIR, S_ISLNK - -import paramiko - -from .. import AbstractFileSystem -from ..utils import infer_storage_options - -logger = logging.getLogger("fsspec.sftp") - - -class SFTPFileSystem(AbstractFileSystem): - """Files over SFTP/SSH - - Peer-to-peer filesystem over SSH using paramiko. - - Note: if using this with the ``open`` or ``open_files``, with full URLs, - there is no way to tell if a path is relative, so all paths are assumed - to be absolute. - """ - - protocol = "sftp", "ssh" - - def __init__(self, host, **ssh_kwargs): - """ - - Parameters - ---------- - host: str - Hostname or IP as a string - temppath: str - Location on the server to put files, when within a transaction - ssh_kwargs: dict - Parameters passed on to connection. See details in - https://docs.paramiko.org/en/3.3/api/client.html#paramiko.client.SSHClient.connect - May include port, username, password... - """ - if self._cached: - return - super().__init__(**ssh_kwargs) - self.temppath = ssh_kwargs.pop("temppath", "/tmp") # remote temp directory - self.host = host - self.ssh_kwargs = ssh_kwargs - self._connect() - - def _connect(self): - logger.debug("Connecting to SFTP server %s", self.host) - self.client = paramiko.SSHClient() - self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.client.connect(self.host, **self.ssh_kwargs) - self.ftp = self.client.open_sftp() - - @classmethod - def _strip_protocol(cls, path): - return infer_storage_options(path)["path"] - - @staticmethod - def _get_kwargs_from_urls(urlpath): - out = infer_storage_options(urlpath) - out.pop("path", None) - out.pop("protocol", None) - return out - - def mkdir(self, path, create_parents=True, mode=511): - path = self._strip_protocol(path) - logger.debug("Creating folder %s", path) - if self.exists(path): - raise FileExistsError(f"File exists: {path}") - - if create_parents: - self.makedirs(path) - else: - self.ftp.mkdir(path, mode) - - def makedirs(self, path, exist_ok=False, mode=511): - if self.exists(path) and not exist_ok: - raise FileExistsError(f"File exists: {path}") - - parts = path.split("/") - new_path = "/" if path[:1] == "/" else "" - - for part in parts: - if part: - new_path = f"{new_path}/{part}" if new_path else part - if not self.exists(new_path): - self.ftp.mkdir(new_path, mode) - - def rmdir(self, path): - path = self._strip_protocol(path) - logger.debug("Removing folder %s", path) - self.ftp.rmdir(path) - - def info(self, path): - path = self._strip_protocol(path) - stat = self._decode_stat(self.ftp.stat(path)) - stat["name"] = path - return stat - - @staticmethod - def _decode_stat(stat, parent_path=None): - if S_ISDIR(stat.st_mode): - t = "directory" - elif S_ISLNK(stat.st_mode): - t = "link" - else: - t = "file" - out = { - "name": "", - "size": stat.st_size, - "type": t, - "uid": stat.st_uid, - "gid": stat.st_gid, - "time": datetime.datetime.fromtimestamp( - stat.st_atime, tz=datetime.timezone.utc - ), - "mtime": datetime.datetime.fromtimestamp( - stat.st_mtime, tz=datetime.timezone.utc - ), - } - if parent_path: - out["name"] = "/".join([parent_path.rstrip("/"), stat.filename]) - return out - - def ls(self, path, detail=False): - path = self._strip_protocol(path) - logger.debug("Listing folder %s", path) - stats = [self._decode_stat(stat, path) for stat in self.ftp.listdir_iter(path)] - if detail: - return stats - else: - paths = [stat["name"] for stat in stats] - return sorted(paths) - - def put(self, lpath, rpath, callback=None, **kwargs): - rpath = self._strip_protocol(rpath) - logger.debug("Put file %s into %s", lpath, rpath) - self.ftp.put(lpath, rpath) - - def get_file(self, rpath, lpath, **kwargs): - if self.isdir(rpath): - os.makedirs(lpath, exist_ok=True) - else: - self.ftp.get(self._strip_protocol(rpath), lpath) - - def _open(self, path, mode="rb", block_size=None, **kwargs): - """ - block_size: int or None - If 0, no buffering, if 1, line buffering, if >1, buffer that many - bytes, if None use default from paramiko. - """ - logger.debug("Opening file %s", path) - if kwargs.get("autocommit", True) is False: - # writes to temporary file, move on commit - path2 = "/".join([self.temppath, str(uuid.uuid4())]) - f = self.ftp.open(path2, mode, bufsize=block_size if block_size else -1) - f.temppath = path2 - f.targetpath = path - f.fs = self - f.commit = types.MethodType(commit_a_file, f) - f.discard = types.MethodType(discard_a_file, f) - else: - f = self.ftp.open(path, mode, bufsize=block_size if block_size else -1) - return f - - def _rm(self, path): - if self.isdir(path): - self.ftp.rmdir(path) - else: - self.ftp.remove(path) - - def mv(self, old, new): - new = self._strip_protocol(new) - old = self._strip_protocol(old) - logger.debug("Renaming %s into %s", old, new) - self.ftp.posix_rename(old, new) - - -def commit_a_file(self): - self.fs.mv(self.temppath, self.targetpath) - - -def discard_a_file(self): - self.fs._rm(self.temppath) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/smb.py b/venv/lib/python3.10/site-packages/fsspec/implementations/smb.py deleted file mode 100644 index db6b3f5c3702de90cf121ccca49f3ca2b580df9f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/smb.py +++ /dev/null @@ -1,416 +0,0 @@ -""" -This module contains SMBFileSystem class responsible for handling access to -Windows Samba network shares by using package smbprotocol -""" - -import datetime -import re -import uuid -from stat import S_ISDIR, S_ISLNK - -import smbclient -import smbprotocol.exceptions - -from .. import AbstractFileSystem -from ..utils import infer_storage_options - -# ! pylint: disable=bad-continuation - - -class SMBFileSystem(AbstractFileSystem): - """Allow reading and writing to Windows and Samba network shares. - - When using `fsspec.open()` for getting a file-like object the URI - should be specified as this format: - ``smb://workgroup;user:password@server:port/share/folder/file.csv``. - - Example:: - - >>> import fsspec - >>> with fsspec.open( - ... 'smb://myuser:mypassword@myserver.com/' 'share/folder/file.csv' - ... ) as smbfile: - ... df = pd.read_csv(smbfile, sep='|', header=None) - - Note that you need to pass in a valid hostname or IP address for the host - component of the URL. Do not use the Windows/NetBIOS machine name for the - host component. - - The first component of the path in the URL points to the name of the shared - folder. Subsequent path components will point to the directory/folder/file. - - The URL components ``workgroup`` , ``user``, ``password`` and ``port`` may be - optional. - - .. note:: - - For working this source require `smbprotocol`_ to be installed, e.g.:: - - $ pip install smbprotocol - # or - # pip install smbprotocol[kerberos] - - .. _smbprotocol: https://github.com/jborean93/smbprotocol#requirements - - Note: if using this with the ``open`` or ``open_files``, with full URLs, - there is no way to tell if a path is relative, so all paths are assumed - to be absolute. - """ - - protocol = "smb" - - # pylint: disable=too-many-arguments - def __init__( - self, - host, - port=None, - username=None, - password=None, - timeout=60, - encrypt=None, - share_access=None, - register_session_retries=4, - register_session_retry_wait=1, - register_session_retry_factor=10, - auto_mkdir=False, - **kwargs, - ): - """ - You can use _get_kwargs_from_urls to get some kwargs from - a reasonable SMB url. - - Authentication will be anonymous or integrated if username/password are not - given. - - Parameters - ---------- - host: str - The remote server name/ip to connect to - port: int or None - Port to connect with. Usually 445, sometimes 139. - username: str or None - Username to connect with. Required if Kerberos auth is not being used. - password: str or None - User's password on the server, if using username - timeout: int - Connection timeout in seconds - encrypt: bool - Whether to force encryption or not, once this has been set to True - the session cannot be changed back to False. - share_access: str or None - Specifies the default access applied to file open operations - performed with this file system object. - This affects whether other processes can concurrently open a handle - to the same file. - - - None (the default): exclusively locks the file until closed. - - 'r': Allow other handles to be opened with read access. - - 'w': Allow other handles to be opened with write access. - - 'd': Allow other handles to be opened with delete access. - register_session_retries: int - Number of retries to register a session with the server. Retries are not performed - for authentication errors, as they are considered as invalid credentials and not network - issues. If set to negative value, no register attempts will be performed. - register_session_retry_wait: int - Time in seconds to wait between each retry. Number must be non-negative. - register_session_retry_factor: int - Base factor for the wait time between each retry. The wait time - is calculated using exponential function. For factor=1 all wait times - will be equal to `register_session_retry_wait`. For any number of retries, - the last wait time will be equal to `register_session_retry_wait` and for retries>1 - the first wait time will be equal to `register_session_retry_wait / factor`. - Number must be equal to or greater than 1. Optimal factor is 10. - auto_mkdir: bool - Whether, when opening a file, the directory containing it should - be created (if it doesn't already exist). This is assumed by pyarrow - and zarr-python code. - """ - super().__init__(**kwargs) - self.host = host - self.port = port - self.username = username - self.password = password - self.timeout = timeout - self.encrypt = encrypt - self.temppath = kwargs.pop("temppath", "") - self.share_access = share_access - self.register_session_retries = register_session_retries - if register_session_retry_wait < 0: - raise ValueError( - "register_session_retry_wait must be a non-negative integer" - ) - self.register_session_retry_wait = register_session_retry_wait - if register_session_retry_factor < 1: - raise ValueError( - "register_session_retry_factor must be a positive " - "integer equal to or greater than 1" - ) - self.register_session_retry_factor = register_session_retry_factor - self.auto_mkdir = auto_mkdir - self._connect() - - @property - def _port(self): - return 445 if self.port is None else self.port - - def _connect(self): - import time - - if self.register_session_retries <= -1: - return - - retried_errors = [] - - wait_time = self.register_session_retry_wait - n_waits = ( - self.register_session_retries - 1 - ) # -1 = No wait time after the last retry - factor = self.register_session_retry_factor - - # Generate wait times for each retry attempt. - # Wait times are calculated using exponential function. For factor=1 all wait times - # will be equal to `wait`. For any number of retries the last wait time will be - # equal to `wait` and for retries>2 the first wait time will be equal to `wait / factor`. - wait_times = iter( - factor ** (n / n_waits - 1) * wait_time for n in range(0, n_waits + 1) - ) - - for attempt in range(self.register_session_retries + 1): - try: - smbclient.register_session( - self.host, - username=self.username, - password=self.password, - port=self._port, - encrypt=self.encrypt, - connection_timeout=self.timeout, - ) - return - except ( - smbprotocol.exceptions.SMBAuthenticationError, - smbprotocol.exceptions.LogonFailure, - ): - # These exceptions should not be repeated, as they clearly indicate - # that the credentials are invalid and not a network issue. - raise - except ValueError as exc: - if re.findall(r"\[Errno -\d+]", str(exc)): - # This exception is raised by the smbprotocol.transport:Tcp.connect - # and originates from socket.gaierror (OSError). These exceptions might - # be raised due to network instability. We will retry to connect. - retried_errors.append(exc) - else: - # All another ValueError exceptions should be raised, as they are not - # related to network issues. - raise - except Exception as exc: - # Save the exception and retry to connect. This except might be dropped - # in the future, once all exceptions suited for retry are identified. - retried_errors.append(exc) - - if attempt < self.register_session_retries: - time.sleep(next(wait_times)) - - # Raise last exception to inform user about the connection issues. - # Note: Should we use ExceptionGroup to raise all exceptions? - raise retried_errors[-1] - - @classmethod - def _strip_protocol(cls, path): - return infer_storage_options(path)["path"] - - @staticmethod - def _get_kwargs_from_urls(path): - # smb://workgroup;user:password@host:port/share/folder/file.csv - out = infer_storage_options(path) - out.pop("path", None) - out.pop("protocol", None) - return out - - def mkdir(self, path, create_parents=True, **kwargs): - wpath = _as_unc_path(self.host, path) - if create_parents: - smbclient.makedirs(wpath, exist_ok=False, port=self._port, **kwargs) - else: - smbclient.mkdir(wpath, port=self._port, **kwargs) - - def makedirs(self, path, exist_ok=False): - if _share_has_path(path): - wpath = _as_unc_path(self.host, path) - smbclient.makedirs(wpath, exist_ok=exist_ok, port=self._port) - - def rmdir(self, path): - if _share_has_path(path): - wpath = _as_unc_path(self.host, path) - smbclient.rmdir(wpath, port=self._port) - - def info(self, path, **kwargs): - wpath = _as_unc_path(self.host, path) - stats = smbclient.stat(wpath, port=self._port, **kwargs) - if S_ISDIR(stats.st_mode): - stype = "directory" - elif S_ISLNK(stats.st_mode): - stype = "link" - else: - stype = "file" - res = { - "name": path + "/" if stype == "directory" else path, - "size": stats.st_size, - "type": stype, - "uid": stats.st_uid, - "gid": stats.st_gid, - "time": stats.st_atime, - "mtime": stats.st_mtime, - } - return res - - def created(self, path): - """Return the created timestamp of a file as a datetime.datetime""" - wpath = _as_unc_path(self.host, path) - stats = smbclient.stat(wpath, port=self._port) - return datetime.datetime.fromtimestamp(stats.st_ctime, tz=datetime.timezone.utc) - - def modified(self, path): - """Return the modified timestamp of a file as a datetime.datetime""" - wpath = _as_unc_path(self.host, path) - stats = smbclient.stat(wpath, port=self._port) - return datetime.datetime.fromtimestamp(stats.st_mtime, tz=datetime.timezone.utc) - - def ls(self, path, detail=True, **kwargs): - unc = _as_unc_path(self.host, path) - listed = smbclient.listdir(unc, port=self._port, **kwargs) - dirs = ["/".join([path.rstrip("/"), p]) for p in listed] - if detail: - dirs = [self.info(d) for d in dirs] - return dirs - - # pylint: disable=too-many-arguments - def _open( - self, - path, - mode="rb", - block_size=-1, - autocommit=True, - cache_options=None, - **kwargs, - ): - """ - block_size: int or None - If 0, no buffering, 1, line buffering, >1, buffer that many bytes - - Notes - ----- - By specifying 'share_access' in 'kwargs' it is possible to override the - default shared access setting applied in the constructor of this object. - """ - if self.auto_mkdir and "w" in mode: - self.makedirs(self._parent(path), exist_ok=True) - bls = block_size if block_size is not None and block_size >= 0 else -1 - wpath = _as_unc_path(self.host, path) - share_access = kwargs.pop("share_access", self.share_access) - if "w" in mode and autocommit is False: - temp = _as_temp_path(self.host, path, self.temppath) - return SMBFileOpener( - wpath, temp, mode, port=self._port, block_size=bls, **kwargs - ) - return smbclient.open_file( - wpath, - mode, - buffering=bls, - share_access=share_access, - port=self._port, - **kwargs, - ) - - def copy(self, path1, path2, **kwargs): - """Copy within two locations in the same filesystem""" - wpath1 = _as_unc_path(self.host, path1) - wpath2 = _as_unc_path(self.host, path2) - if self.auto_mkdir: - self.makedirs(self._parent(path2), exist_ok=True) - smbclient.copyfile(wpath1, wpath2, port=self._port, **kwargs) - - def _rm(self, path): - if _share_has_path(path): - wpath = _as_unc_path(self.host, path) - stats = smbclient.stat(wpath, port=self._port) - if S_ISDIR(stats.st_mode): - smbclient.rmdir(wpath, port=self._port) - else: - smbclient.remove(wpath, port=self._port) - - def mv(self, path1, path2, recursive=None, maxdepth=None, **kwargs): - wpath1 = _as_unc_path(self.host, path1) - wpath2 = _as_unc_path(self.host, path2) - smbclient.rename(wpath1, wpath2, port=self._port, **kwargs) - - -def _as_unc_path(host, path): - rpath = path.replace("/", "\\") - unc = f"\\\\{host}{rpath}" - return unc - - -def _as_temp_path(host, path, temppath): - share = path.split("/")[1] - temp_file = f"/{share}{temppath}/{uuid.uuid4()}" - unc = _as_unc_path(host, temp_file) - return unc - - -def _share_has_path(path): - parts = path.count("/") - if path.endswith("/"): - return parts > 2 - return parts > 1 - - -class SMBFileOpener: - """writes to remote temporary file, move on commit""" - - def __init__(self, path, temp, mode, port=445, block_size=-1, **kwargs): - self.path = path - self.temp = temp - self.mode = mode - self.block_size = block_size - self.kwargs = kwargs - self.smbfile = None - self._incontext = False - self.port = port - self._open() - - def _open(self): - if self.smbfile is None or self.smbfile.closed: - self.smbfile = smbclient.open_file( - self.temp, - self.mode, - port=self.port, - buffering=self.block_size, - **self.kwargs, - ) - - def commit(self): - """Move temp file to definitive on success.""" - # TODO: use transaction support in SMB protocol - smbclient.replace(self.temp, self.path, port=self.port) - - def discard(self): - """Remove the temp file on failure.""" - smbclient.remove(self.temp, port=self.port) - - def __fspath__(self): - return self.path - - def __iter__(self): - return self.smbfile.__iter__() - - def __getattr__(self, item): - return getattr(self.smbfile, item) - - def __enter__(self): - self._incontext = True - return self.smbfile.__enter__() - - def __exit__(self, exc_type, exc_value, traceback): - self._incontext = False - self.smbfile.__exit__(exc_type, exc_value, traceback) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/tar.py b/venv/lib/python3.10/site-packages/fsspec/implementations/tar.py deleted file mode 100644 index 412e5ba4d2cdea7db090dc96412e697909a38d78..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/tar.py +++ /dev/null @@ -1,124 +0,0 @@ -import logging -import tarfile - -import fsspec -from fsspec.archive import AbstractArchiveFileSystem -from fsspec.compression import compr -from fsspec.utils import infer_compression - -typemap = {b"0": "file", b"5": "directory"} - -logger = logging.getLogger("tar") - - -class TarFileSystem(AbstractArchiveFileSystem): - """Compressed Tar archives as a file-system (read-only) - - Supports the following formats: - tar.gz, tar.bz2, tar.xz - """ - - root_marker = "" - protocol = "tar" - cachable = False - - def __init__( - self, - fo="", - index_store=None, - target_options=None, - target_protocol=None, - compression=None, - **kwargs, - ): - super().__init__(**kwargs) - target_options = target_options or {} - - if isinstance(fo, str): - self.of = fsspec.open(fo, protocol=target_protocol, **target_options) - fo = self.of.open() # keep the reference - - # Try to infer compression. - if compression is None: - name = None - - # Try different ways to get hold of the filename. `fo` might either - # be a `fsspec.LocalFileOpener`, an `io.BufferedReader` or an - # `fsspec.AbstractFileSystem` instance. - try: - # Amended io.BufferedReader or similar. - # This uses a "protocol extension" where original filenames are - # propagated to archive-like filesystems in order to let them - # infer the right compression appropriately. - if hasattr(fo, "original"): - name = fo.original - - # fsspec.LocalFileOpener - elif hasattr(fo, "path"): - name = fo.path - - # io.BufferedReader - elif hasattr(fo, "name"): - name = fo.name - - # fsspec.AbstractFileSystem - elif hasattr(fo, "info"): - name = fo.info()["name"] - - except Exception as ex: - logger.warning( - f"Unable to determine file name, not inferring compression: {ex}" - ) - - if name is not None: - compression = infer_compression(name) - logger.info(f"Inferred compression {compression} from file name {name}") - - if compression is not None: - # TODO: tarfile already implements compression with modes like "'r:gz'", - # but then would seek to offset in the file work? - fo = compr[compression](fo) - - self._fo_ref = fo - self.fo = fo # the whole instance is a context - self.tar = tarfile.TarFile(fileobj=self.fo) - self.dir_cache = None - - self.index_store = index_store - self.index = None - self._index() - - def _index(self): - # TODO: load and set saved index, if exists - out = {} - for ti in self.tar: - info = ti.get_info() - info["type"] = typemap.get(info["type"], "file") - name = ti.get_info()["name"].rstrip("/") - out[name] = (info, ti.offset_data) - - self.index = out - # TODO: save index to self.index_store here, if set - - def _get_dirs(self): - if self.dir_cache is not None: - return - - # This enables ls to get directories as children as well as files - self.dir_cache = { - dirname: {"name": dirname, "size": 0, "type": "directory"} - for dirname in self._all_dirnames(self.tar.getnames()) - } - for member in self.tar.getmembers(): - info = member.get_info() - info["name"] = info["name"].rstrip("/") - info["type"] = typemap.get(info["type"], "file") - self.dir_cache[info["name"]] = info - - def _open(self, path, mode="rb", **kwargs): - if mode != "rb": - raise ValueError("Read-only filesystem implementation") - details, offset = self.index[path] - if details["type"] != "file": - raise ValueError("Can only handle regular files") - return self.tar.extractfile(path) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/webhdfs.py b/venv/lib/python3.10/site-packages/fsspec/implementations/webhdfs.py deleted file mode 100644 index e3048b6a3638cf34e400804a3057521e720b6e81..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/webhdfs.py +++ /dev/null @@ -1,503 +0,0 @@ -# https://hadoop.apache.org/docs/r1.0.4/webhdfs.html - -import logging -import os -import secrets -import shutil -import tempfile -import uuid -from contextlib import suppress -from datetime import datetime -from urllib.parse import quote - -import requests - -from ..spec import AbstractBufferedFile, AbstractFileSystem -from ..utils import infer_storage_options, tokenize - -logger = logging.getLogger("webhdfs") - - -class WebHDFS(AbstractFileSystem): - """ - Interface to HDFS over HTTP using the WebHDFS API. Supports also HttpFS gateways. - - Four auth mechanisms are supported: - - insecure: no auth is done, and the user is assumed to be whoever they - say they are (parameter ``user``), or a predefined value such as - "dr.who" if not given - spnego: when kerberos authentication is enabled, auth is negotiated by - requests_kerberos https://github.com/requests/requests-kerberos . - This establishes a session based on existing kinit login and/or - specified principal/password; parameters are passed with ``kerb_kwargs`` - token: uses an existing Hadoop delegation token from another secured - service. Indeed, this client can also generate such tokens when - not insecure. Note that tokens expire, but can be renewed (by a - previously specified user) and may allow for proxying. - basic-auth: used when both parameter ``user`` and parameter ``password`` - are provided. - - """ - - tempdir = str(tempfile.gettempdir()) - protocol = "webhdfs", "webHDFS" - - def __init__( - self, - host, - port=50070, - kerberos=False, - token=None, - user=None, - password=None, - proxy_to=None, - kerb_kwargs=None, - data_proxy=None, - use_https=False, - session_cert=None, - session_verify=True, - **kwargs, - ): - """ - Parameters - ---------- - host: str - Name-node address - port: int - Port for webHDFS - kerberos: bool - Whether to authenticate with kerberos for this connection - token: str or None - If given, use this token on every call to authenticate. A user - and user-proxy may be encoded in the token and should not be also - given - user: str or None - If given, assert the user name to connect with - password: str or None - If given, assert the password to use for basic auth. If password - is provided, user must be provided also - proxy_to: str or None - If given, the user has the authority to proxy, and this value is - the user in who's name actions are taken - kerb_kwargs: dict - Any extra arguments for HTTPKerberosAuth, see - ``_ - data_proxy: dict, callable or None - If given, map data-node addresses. This can be necessary if the - HDFS cluster is behind a proxy, running on Docker or otherwise has - a mismatch between the host-names given by the name-node and the - address by which to refer to them from the client. If a dict, - maps host names ``host->data_proxy[host]``; if a callable, full - URLs are passed, and function must conform to - ``url->data_proxy(url)``. - use_https: bool - Whether to connect to the Name-node using HTTPS instead of HTTP - session_cert: str or Tuple[str, str] or None - Path to a certificate file, or tuple of (cert, key) files to use - for the requests.Session - session_verify: str, bool or None - Path to a certificate file to use for verifying the requests.Session. - kwargs - """ - if self._cached: - return - super().__init__(**kwargs) - self.url = f"{'https' if use_https else 'http'}://{host}:{port}/webhdfs/v1" - self.kerb = kerberos - self.kerb_kwargs = kerb_kwargs or {} - self.pars = {} - self.proxy = data_proxy or {} - if token is not None: - if user is not None or proxy_to is not None: - raise ValueError( - "If passing a delegation token, must not set " - "user or proxy_to, as these are encoded in the" - " token" - ) - self.pars["delegation"] = token - self.user = user - self.password = password - - if password is not None: - if user is None: - raise ValueError( - "If passing a password, the user must also be" - "set in order to set up the basic-auth" - ) - else: - if user is not None: - self.pars["user.name"] = user - - if proxy_to is not None: - self.pars["doas"] = proxy_to - if kerberos and user is not None: - raise ValueError( - "If using Kerberos auth, do not specify the " - "user, this is handled by kinit." - ) - - self.session_cert = session_cert - self.session_verify = session_verify - - self._connect() - - self._fsid = f"webhdfs_{tokenize(host, port)}" - - @property - def fsid(self): - return self._fsid - - def _connect(self): - self.session = requests.Session() - - if self.session_cert: - self.session.cert = self.session_cert - - self.session.verify = self.session_verify - - if self.kerb: - from requests_kerberos import HTTPKerberosAuth - - self.session.auth = HTTPKerberosAuth(**self.kerb_kwargs) - - if self.user is not None and self.password is not None: - from requests.auth import HTTPBasicAuth - - self.session.auth = HTTPBasicAuth(self.user, self.password) - - def _call(self, op, method="get", path=None, data=None, redirect=True, **kwargs): - path = self._strip_protocol(path) if path is not None else "" - url = self._apply_proxy(self.url + quote(path, safe="/=")) - args = kwargs.copy() - args.update(self.pars) - args["op"] = op.upper() - logger.debug("sending %s with %s", url, method) - out = self.session.request( - method=method.upper(), - url=url, - params=args, - data=data, - allow_redirects=redirect, - ) - if out.status_code in [400, 401, 403, 404, 500]: - try: - err = out.json() - msg = err["RemoteException"]["message"] - exp = err["RemoteException"]["exception"] - except (ValueError, KeyError): - pass - else: - if exp in ["IllegalArgumentException", "UnsupportedOperationException"]: - raise ValueError(msg) - elif exp in ["SecurityException", "AccessControlException"]: - raise PermissionError(msg) - elif exp in ["FileNotFoundException"]: - raise FileNotFoundError(msg) - else: - raise RuntimeError(msg) - out.raise_for_status() - return out - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - replication=None, - permissions=None, - **kwargs, - ): - """ - - Parameters - ---------- - path: str - File location - mode: str - 'rb', 'wb', etc. - block_size: int - Client buffer size for read-ahead or write buffer - autocommit: bool - If False, writes to temporary file that only gets put in final - location upon commit - replication: int - Number of copies of file on the cluster, write mode only - permissions: str or int - posix permissions, write mode only - kwargs - - Returns - ------- - WebHDFile instance - """ - block_size = block_size or self.blocksize - return WebHDFile( - self, - path, - mode=mode, - block_size=block_size, - tempdir=self.tempdir, - autocommit=autocommit, - replication=replication, - permissions=permissions, - ) - - @staticmethod - def _process_info(info): - info["type"] = info["type"].lower() - info["size"] = info["length"] - return info - - @classmethod - def _strip_protocol(cls, path): - return infer_storage_options(path)["path"] - - @staticmethod - def _get_kwargs_from_urls(urlpath): - out = infer_storage_options(urlpath) - out.pop("path", None) - out.pop("protocol", None) - if "username" in out: - out["user"] = out.pop("username") - return out - - def info(self, path): - out = self._call("GETFILESTATUS", path=path) - info = out.json()["FileStatus"] - info["name"] = path - return self._process_info(info) - - def created(self, path): - """Return the created timestamp of a file as a datetime.datetime""" - # The API does not provide creation time, so we use modification time - info = self.info(path) - mtime = info.get("modificationTime", None) - if mtime is not None: - return datetime.fromtimestamp(mtime / 1000) - raise RuntimeError("Could not retrieve creation time (modification time).") - - def modified(self, path): - """Return the modified timestamp of a file as a datetime.datetime""" - info = self.info(path) - mtime = info.get("modificationTime", None) - if mtime is not None: - return datetime.fromtimestamp(mtime / 1000) - raise RuntimeError("Could not retrieve modification time.") - - def ls(self, path, detail=False, **kwargs): - out = self._call("LISTSTATUS", path=path) - infos = out.json()["FileStatuses"]["FileStatus"] - for info in infos: - self._process_info(info) - info["name"] = path.rstrip("/") + "/" + info["pathSuffix"] - if detail: - return sorted(infos, key=lambda i: i["name"]) - else: - return sorted(info["name"] for info in infos) - - def content_summary(self, path): - """Total numbers of files, directories and bytes under path""" - out = self._call("GETCONTENTSUMMARY", path=path) - return out.json()["ContentSummary"] - - def ukey(self, path): - """Checksum info of file, giving method and result""" - out = self._call("GETFILECHECKSUM", path=path, redirect=False) - if "Location" in out.headers: - location = self._apply_proxy(out.headers["Location"]) - out2 = self.session.get(location) - out2.raise_for_status() - return out2.json()["FileChecksum"] - else: - out.raise_for_status() - return out.json()["FileChecksum"] - - def home_directory(self): - """Get user's home directory""" - out = self._call("GETHOMEDIRECTORY") - return out.json()["Path"] - - def get_delegation_token(self, renewer=None): - """Retrieve token which can give the same authority to other uses - - Parameters - ---------- - renewer: str or None - User who may use this token; if None, will be current user - """ - if renewer: - out = self._call("GETDELEGATIONTOKEN", renewer=renewer) - else: - out = self._call("GETDELEGATIONTOKEN") - t = out.json()["Token"] - if t is None: - raise ValueError("No token available for this user/security context") - return t["urlString"] - - def renew_delegation_token(self, token): - """Make token live longer. Returns new expiry time""" - out = self._call("RENEWDELEGATIONTOKEN", method="put", token=token) - return out.json()["long"] - - def cancel_delegation_token(self, token): - """Stop the token from being useful""" - self._call("CANCELDELEGATIONTOKEN", method="put", token=token) - - def chmod(self, path, mod): - """Set the permission at path - - Parameters - ---------- - path: str - location to set (file or directory) - mod: str or int - posix epresentation or permission, give as oct string, e.g, '777' - or 0o777 - """ - self._call("SETPERMISSION", method="put", path=path, permission=mod) - - def chown(self, path, owner=None, group=None): - """Change owning user and/or group""" - kwargs = {} - if owner is not None: - kwargs["owner"] = owner - if group is not None: - kwargs["group"] = group - self._call("SETOWNER", method="put", path=path, **kwargs) - - def set_replication(self, path, replication): - """ - Set file replication factor - - Parameters - ---------- - path: str - File location (not for directories) - replication: int - Number of copies of file on the cluster. Should be smaller than - number of data nodes; normally 3 on most systems. - """ - self._call("SETREPLICATION", path=path, method="put", replication=replication) - - def mkdir(self, path, **kwargs): - self._call("MKDIRS", method="put", path=path) - - def makedirs(self, path, exist_ok=False): - if exist_ok is False and self.exists(path): - raise FileExistsError(path) - self.mkdir(path) - - def mv(self, path1, path2, **kwargs): - self._call("RENAME", method="put", path=path1, destination=path2) - - def rm(self, path, recursive=False, **kwargs): - self._call( - "DELETE", - method="delete", - path=path, - recursive="true" if recursive else "false", - ) - - def rm_file(self, path, **kwargs): - self.rm(path) - - def cp_file(self, lpath, rpath, **kwargs): - with self.open(lpath) as lstream: - tmp_fname = "/".join([self._parent(rpath), f".tmp.{secrets.token_hex(16)}"]) - # Perform an atomic copy (stream to a temporary file and - # move it to the actual destination). - try: - with self.open(tmp_fname, "wb") as rstream: - shutil.copyfileobj(lstream, rstream) - self.mv(tmp_fname, rpath) - except BaseException: - with suppress(FileNotFoundError): - self.rm(tmp_fname) - raise - - def _apply_proxy(self, location): - if self.proxy and callable(self.proxy): - location = self.proxy(location) - elif self.proxy: - # as a dict - for k, v in self.proxy.items(): - location = location.replace(k, v, 1) - return location - - -class WebHDFile(AbstractBufferedFile): - """A file living in HDFS over webHDFS""" - - def __init__(self, fs, path, **kwargs): - super().__init__(fs, path, **kwargs) - kwargs = kwargs.copy() - if kwargs.get("permissions", None) is None: - kwargs.pop("permissions", None) - if kwargs.get("replication", None) is None: - kwargs.pop("replication", None) - self.permissions = kwargs.pop("permissions", 511) - tempdir = kwargs.pop("tempdir") - if kwargs.pop("autocommit", False) is False: - self.target = self.path - self.path = os.path.join(tempdir, str(uuid.uuid4())) - - def _upload_chunk(self, final=False): - """Write one part of a multi-block file upload - - Parameters - ========== - final: bool - This is the last block, so should complete file, if - self.autocommit is True. - """ - out = self.fs.session.post( - self.location, - data=self.buffer.getvalue(), - headers={"content-type": "application/octet-stream"}, - ) - out.raise_for_status() - return True - - def _initiate_upload(self): - """Create remote file/upload""" - kwargs = self.kwargs.copy() - if "a" in self.mode: - op, method = "APPEND", "POST" - else: - op, method = "CREATE", "PUT" - kwargs["overwrite"] = "true" - out = self.fs._call(op, method, self.path, redirect=False, **kwargs) - location = self.fs._apply_proxy(out.headers["Location"]) - if "w" in self.mode: - # create empty file to append to - out2 = self.fs.session.put( - location, headers={"content-type": "application/octet-stream"} - ) - out2.raise_for_status() - # after creating empty file, change location to append to - out2 = self.fs._call("APPEND", "POST", self.path, redirect=False, **kwargs) - self.location = self.fs._apply_proxy(out2.headers["Location"]) - - def _fetch_range(self, start, end): - start = max(start, 0) - end = min(self.size, end) - if start >= end or start >= self.size: - return b"" - out = self.fs._call( - "OPEN", path=self.path, offset=start, length=end - start, redirect=False - ) - out.raise_for_status() - if "Location" in out.headers: - location = out.headers["Location"] - out2 = self.fs.session.get(self.fs._apply_proxy(location)) - return out2.content - else: - return out.content - - def commit(self): - self.fs.mv(self.path, self.target) - - def discard(self): - self.fs.rm(self.path) diff --git a/venv/lib/python3.10/site-packages/fsspec/implementations/zip.py b/venv/lib/python3.10/site-packages/fsspec/implementations/zip.py deleted file mode 100644 index d55d54665c1f7c097c287e7432e0aa615955053c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/implementations/zip.py +++ /dev/null @@ -1,181 +0,0 @@ -import os -import zipfile - -import fsspec -from fsspec.archive import AbstractArchiveFileSystem - - -class ZipFileSystem(AbstractArchiveFileSystem): - """Read/Write contents of ZIP archive as a file-system - - Keeps file object open while instance lives. - - This class is pickleable, but not necessarily thread-safe - """ - - root_marker = "" - protocol = "zip" - cachable = False - - def __init__( - self, - fo="", - mode="r", - target_protocol=None, - target_options=None, - compression=zipfile.ZIP_STORED, - allowZip64=True, - compresslevel=None, - **kwargs, - ): - """ - Parameters - ---------- - fo: str or file-like - Contains ZIP, and must exist. If a str, will fetch file using - :meth:`~fsspec.open_files`, which must return one file exactly. - mode: str - Accept: "r", "w", "a" - target_protocol: str (optional) - If ``fo`` is a string, this value can be used to override the - FS protocol inferred from a URL - target_options: dict (optional) - Kwargs passed when instantiating the target FS, if ``fo`` is - a string. - compression, allowZip64, compresslevel: passed to ZipFile - Only relevant when creating a ZIP - """ - super().__init__(self, **kwargs) - if mode not in set("rwa"): - raise ValueError(f"mode '{mode}' no understood") - self.mode = mode - if isinstance(fo, (str, os.PathLike)): - if mode == "a": - m = "r+b" - else: - m = mode + "b" - fo = fsspec.open( - fo, mode=m, protocol=target_protocol, **(target_options or {}) - ) - self.force_zip_64 = allowZip64 - self.of = fo - self.fo = fo.__enter__() # the whole instance is a context - self.zip = zipfile.ZipFile( - self.fo, - mode=mode, - compression=compression, - allowZip64=allowZip64, - compresslevel=compresslevel, - ) - self.dir_cache = None - - @classmethod - def _strip_protocol(cls, path): - # zip file paths are always relative to the archive root - return super()._strip_protocol(path).lstrip("/") - - def __del__(self): - if hasattr(self, "zip"): - self.close() - del self.zip - - def close(self): - """Commits any write changes to the file. Done on ``del`` too.""" - self.zip.close() - - def _get_dirs(self): - if self.dir_cache is None or self.mode in set("wa"): - # when writing, dir_cache is always in the ZipFile's attributes, - # not read from the file. - files = self.zip.infolist() - self.dir_cache = { - dirname.rstrip("/"): { - "name": dirname.rstrip("/"), - "size": 0, - "type": "directory", - } - for dirname in self._all_dirnames(self.zip.namelist()) - } - for z in files: - f = {s: getattr(z, s, None) for s in zipfile.ZipInfo.__slots__} - f.update( - { - "name": z.filename.rstrip("/"), - "size": z.file_size, - "type": ("directory" if z.is_dir() else "file"), - } - ) - self.dir_cache[f["name"]] = f - - def pipe_file(self, path, value, **kwargs): - # override upstream, because we know the exact file size in this case - self.zip.writestr(path, value, **kwargs) - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - **kwargs, - ): - path = self._strip_protocol(path) - if "r" in mode and self.mode in set("wa"): - if self.exists(path): - raise OSError("ZipFS can only be open for reading or writing, not both") - raise FileNotFoundError(path) - if "r" in self.mode and "w" in mode: - raise OSError("ZipFS can only be open for reading or writing, not both") - out = self.zip.open(path, mode.strip("b"), force_zip64=self.force_zip_64) - if "r" in mode: - info = self.info(path) - out.size = info["size"] - out.name = info["name"] - return out - - def find(self, path, maxdepth=None, withdirs=False, detail=False, **kwargs): - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - - def to_parts(_path: str): - return list(filter(None, _path.replace("\\", "/").split("/"))) - - if not isinstance(path, str): - path = str(path) - - # Remove the leading slash, as the zip file paths are always - # given without a leading slash - path = path.lstrip("/") - path_parts = to_parts(path) - path_depth = len(path_parts) - - self._get_dirs() - - result = {} - # To match posix find, if an exact file name is given, we should - # return only that file - if path in self.dir_cache and self.dir_cache[path]["type"] == "file": - result[path] = self.dir_cache[path] - return result if detail else [path] - - for file_path, file_info in self.dir_cache.items(): - if len(file_parts := to_parts(file_path)) < path_depth or any( - a != b for a, b in zip(path_parts, file_parts) - ): - # skip parent folders and mismatching paths - continue - - if file_info["type"] == "directory": - if withdirs and file_path not in result: - result[file_path.strip("/")] = file_info - continue - - if file_path not in result: - result[file_path] = file_info if detail else None - - if maxdepth: - result = { - k: v for k, v in result.items() if k.count("/") < maxdepth + path_depth - } - return result if detail else sorted(result) diff --git a/venv/lib/python3.10/site-packages/fsspec/json.py b/venv/lib/python3.10/site-packages/fsspec/json.py deleted file mode 100644 index 5c53a24913d0b28f4b53a163b97ff8f58abeb031..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/json.py +++ /dev/null @@ -1,112 +0,0 @@ -import json -from collections.abc import Callable, Mapping, Sequence -from contextlib import suppress -from pathlib import PurePath -from typing import Any, ClassVar - -from .registry import _import_class, get_filesystem_class -from .spec import AbstractFileSystem - - -class FilesystemJSONEncoder(json.JSONEncoder): - include_password: ClassVar[bool] = True - - def default(self, o: Any) -> Any: - if isinstance(o, AbstractFileSystem): - return o.to_dict(include_password=self.include_password) - if isinstance(o, PurePath): - cls = type(o) - return {"cls": f"{cls.__module__}.{cls.__name__}", "str": str(o)} - - return super().default(o) - - def make_serializable(self, obj: Any) -> Any: - """ - Recursively converts an object so that it can be JSON serialized via - :func:`json.dumps` and :func:`json.dump`, without actually calling - said functions. - """ - if isinstance(obj, (str, int, float, bool)): - return obj - if isinstance(obj, Mapping): - return {k: self.make_serializable(v) for k, v in obj.items()} - if isinstance(obj, Sequence): - return [self.make_serializable(v) for v in obj] - - return self.default(obj) - - -class FilesystemJSONDecoder(json.JSONDecoder): - def __init__( - self, - *, - object_hook: Callable[[dict[str, Any]], Any] | None = None, - parse_float: Callable[[str], Any] | None = None, - parse_int: Callable[[str], Any] | None = None, - parse_constant: Callable[[str], Any] | None = None, - strict: bool = True, - object_pairs_hook: Callable[[list[tuple[str, Any]]], Any] | None = None, - ) -> None: - self.original_object_hook = object_hook - - super().__init__( - object_hook=self.custom_object_hook, - parse_float=parse_float, - parse_int=parse_int, - parse_constant=parse_constant, - strict=strict, - object_pairs_hook=object_pairs_hook, - ) - - @classmethod - def try_resolve_path_cls(cls, dct: dict[str, Any]): - with suppress(Exception): - fqp = dct["cls"] - - path_cls = _import_class(fqp) - - if issubclass(path_cls, PurePath): - return path_cls - - return None - - @classmethod - def try_resolve_fs_cls(cls, dct: dict[str, Any]): - with suppress(Exception): - if "cls" in dct: - try: - fs_cls = _import_class(dct["cls"]) - if issubclass(fs_cls, AbstractFileSystem): - return fs_cls - except Exception: - if "protocol" in dct: # Fallback if cls cannot be imported - return get_filesystem_class(dct["protocol"]) - - raise - - return None - - def custom_object_hook(self, dct: dict[str, Any]): - if "cls" in dct: - if (obj_cls := self.try_resolve_fs_cls(dct)) is not None: - return AbstractFileSystem.from_dict(dct) - if (obj_cls := self.try_resolve_path_cls(dct)) is not None: - return obj_cls(dct["str"]) - - if self.original_object_hook is not None: - return self.original_object_hook(dct) - - return dct - - def unmake_serializable(self, obj: Any) -> Any: - """ - Inverse function of :meth:`FilesystemJSONEncoder.make_serializable`. - """ - if isinstance(obj, dict): - obj = self.custom_object_hook(obj) - if isinstance(obj, dict): - return {k: self.unmake_serializable(v) for k, v in obj.items()} - if isinstance(obj, (list, tuple)): - return [self.unmake_serializable(v) for v in obj] - - return obj diff --git a/venv/lib/python3.10/site-packages/fsspec/mapping.py b/venv/lib/python3.10/site-packages/fsspec/mapping.py deleted file mode 100644 index 752eef35273b13eded7297e2e801b58e436a25b1..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/mapping.py +++ /dev/null @@ -1,251 +0,0 @@ -import array -import logging -import posixpath -import warnings -from collections.abc import MutableMapping -from functools import cached_property - -from fsspec.core import url_to_fs - -logger = logging.getLogger("fsspec.mapping") - - -class FSMap(MutableMapping): - """Wrap a FileSystem instance as a mutable wrapping. - - The keys of the mapping become files under the given root, and the - values (which must be bytes) the contents of those files. - - Parameters - ---------- - root: string - prefix for all the files - fs: FileSystem instance - check: bool (=True) - performs a touch at the location, to check for write access. - - Examples - -------- - >>> fs = FileSystem(**parameters) # doctest: +SKIP - >>> d = FSMap('my-data/path/', fs) # doctest: +SKIP - or, more likely - >>> d = fs.get_mapper('my-data/path/') - - >>> d['loc1'] = b'Hello World' # doctest: +SKIP - >>> list(d.keys()) # doctest: +SKIP - ['loc1'] - >>> d['loc1'] # doctest: +SKIP - b'Hello World' - """ - - def __init__(self, root, fs, check=False, create=False, missing_exceptions=None): - self.fs = fs - self.root = fs._strip_protocol(root) - self._root_key_to_str = fs._strip_protocol(posixpath.join(root, "x"))[:-1] - if missing_exceptions is None: - missing_exceptions = ( - FileNotFoundError, - IsADirectoryError, - NotADirectoryError, - ) - self.missing_exceptions = missing_exceptions - self.check = check - self.create = create - if create: - if not self.fs.exists(root): - self.fs.mkdir(root) - if check: - if not self.fs.exists(root): - raise ValueError( - f"Path {root} does not exist. Create " - f" with the ``create=True`` keyword" - ) - self.fs.touch(root + "/a") - self.fs.rm(root + "/a") - - @cached_property - def dirfs(self): - """dirfs instance that can be used with the same keys as the mapper""" - from .implementations.dirfs import DirFileSystem - - return DirFileSystem(path=self._root_key_to_str, fs=self.fs) - - def clear(self): - """Remove all keys below root - empties out mapping""" - logger.info("Clear mapping at %s", self.root) - try: - self.fs.rm(self.root, True) - self.fs.mkdir(self.root) - except: # noqa: E722 - pass - - def getitems(self, keys, on_error="raise"): - """Fetch multiple items from the store - - If the backend is async-able, this might proceed concurrently - - Parameters - ---------- - keys: list(str) - They keys to be fetched - on_error : "raise", "omit", "return" - If raise, an underlying exception will be raised (converted to KeyError - if the type is in self.missing_exceptions); if omit, keys with exception - will simply not be included in the output; if "return", all keys are - included in the output, but the value will be bytes or an exception - instance. - - Returns - ------- - dict(key, bytes|exception) - """ - keys2 = [self._key_to_str(k) for k in keys] - oe = on_error if on_error == "raise" else "return" - try: - out = self.fs.cat(keys2, on_error=oe) - if isinstance(out, bytes): - out = {keys2[0]: out} - except self.missing_exceptions as e: - raise KeyError from e - out = { - k: (KeyError() if isinstance(v, self.missing_exceptions) else v) - for k, v in out.items() - } - return { - key: out[k2] if on_error == "raise" else out.get(k2, KeyError(k2)) - for key, k2 in zip(keys, keys2) - if on_error == "return" or not isinstance(out[k2], BaseException) - } - - def setitems(self, values_dict): - """Set the values of multiple items in the store - - Parameters - ---------- - values_dict: dict(str, bytes) - """ - values = {self._key_to_str(k): maybe_convert(v) for k, v in values_dict.items()} - self.fs.pipe(values) - - def delitems(self, keys): - """Remove multiple keys from the store""" - self.fs.rm([self._key_to_str(k) for k in keys]) - - def _key_to_str(self, key): - """Generate full path for the key""" - if not isinstance(key, str): - # raise TypeError("key must be of type `str`, got `{type(key).__name__}`" - warnings.warn( - "from fsspec 2023.5 onward FSMap non-str keys will raise TypeError", - DeprecationWarning, - ) - if isinstance(key, list): - key = tuple(key) - key = str(key) - return f"{self._root_key_to_str}{key}".rstrip("/") - - def _str_to_key(self, s): - """Strip path of to leave key name""" - return s[len(self.root) :].lstrip("/") - - def __getitem__(self, key, default=None): - """Retrieve data""" - k = self._key_to_str(key) - try: - result = self.fs.cat(k) - except self.missing_exceptions as exc: - if default is not None: - return default - raise KeyError(key) from exc - return result - - def pop(self, key, default=None): - """Pop data""" - result = self.__getitem__(key, default) - try: - del self[key] - except KeyError: - pass - return result - - def __setitem__(self, key, value): - """Store value in key""" - key = self._key_to_str(key) - self.fs.mkdirs(self.fs._parent(key), exist_ok=True) - self.fs.pipe_file(key, maybe_convert(value)) - - def __iter__(self): - return (self._str_to_key(x) for x in self.fs.find(self.root)) - - def __len__(self): - return len(self.fs.find(self.root)) - - def __delitem__(self, key): - """Remove key""" - try: - self.fs.rm(self._key_to_str(key)) - except Exception as exc: - raise KeyError from exc - - def __contains__(self, key): - """Does key exist in mapping?""" - path = self._key_to_str(key) - return self.fs.isfile(path) - - def __reduce__(self): - return FSMap, (self.root, self.fs, False, False, self.missing_exceptions) - - -def maybe_convert(value): - if isinstance(value, array.array) or hasattr(value, "__array__"): - # bytes-like things - if hasattr(value, "dtype") and value.dtype.kind in "Mm": - # The buffer interface doesn't support datetime64/timdelta64 numpy - # arrays - value = value.view("int64") - value = bytes(memoryview(value)) - return value - - -def get_mapper( - url="", - check=False, - create=False, - missing_exceptions=None, - alternate_root=None, - **kwargs, -): - """Create key-value interface for given URL and options - - The URL will be of the form "protocol://location" and point to the root - of the mapper required. All keys will be file-names below this location, - and their values the contents of each key. - - Also accepts compound URLs like zip::s3://bucket/file.zip , see ``fsspec.open``. - - Parameters - ---------- - url: str - Root URL of mapping - check: bool - Whether to attempt to read from the location before instantiation, to - check that the mapping does exist - create: bool - Whether to make the directory corresponding to the root before - instantiating - missing_exceptions: None or tuple - If given, these exception types will be regarded as missing keys and - return KeyError when trying to read data. By default, you get - (FileNotFoundError, IsADirectoryError, NotADirectoryError) - alternate_root: None or str - In cases of complex URLs, the parser may fail to pick the correct part - for the mapper root, so this arg can override - - Returns - ------- - ``FSMap`` instance, the dict-like key-value store. - """ - # Removing protocol here - could defer to each open() on the backend - fs, urlpath = url_to_fs(url, **kwargs) - root = alternate_root if alternate_root is not None else urlpath - return FSMap(root, fs, check, create, missing_exceptions=missing_exceptions) diff --git a/venv/lib/python3.10/site-packages/fsspec/parquet.py b/venv/lib/python3.10/site-packages/fsspec/parquet.py deleted file mode 100644 index 25f1b702d36a047f15a2095c151ecf86e4fe99ab..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/parquet.py +++ /dev/null @@ -1,572 +0,0 @@ -import io -import json -import warnings - -import fsspec - -from .core import url_to_fs -from .spec import AbstractBufferedFile -from .utils import merge_offset_ranges - -# Parquet-Specific Utilities for fsspec -# -# Most of the functions defined in this module are NOT -# intended for public consumption. The only exception -# to this is `open_parquet_file`, which should be used -# place of `fs.open()` to open parquet-formatted files -# on remote file systems. - - -class AlreadyBufferedFile(AbstractBufferedFile): - def _fetch_range(self, start, end): - raise NotImplementedError - - -def open_parquet_files( - path: list[str], - fs: None | fsspec.AbstractFileSystem = None, - metadata=None, - columns: None | list[str] = None, - row_groups: None | list[int] = None, - storage_options: None | dict = None, - engine: str = "auto", - max_gap: int = 64_000, - max_block: int = 256_000_000, - footer_sample_size: int = 1_000_000, - filters: None | list[list[list[str]]] = None, - **kwargs, -): - """ - Return a file-like object for a single Parquet file. - - The specified parquet `engine` will be used to parse the - footer metadata, and determine the required byte ranges - from the file. The target path will then be opened with - the "parts" (`KnownPartsOfAFile`) caching strategy. - - Note that this method is intended for usage with remote - file systems, and is unlikely to improve parquet-read - performance on local file systems. - - Parameters - ---------- - path: str - Target file path. - metadata: Any, optional - Parquet metadata object. Object type must be supported - by the backend parquet engine. For now, only the "fastparquet" - engine supports an explicit `ParquetFile` metadata object. - If a metadata object is supplied, the remote footer metadata - will not need to be transferred into local memory. - fs: AbstractFileSystem, optional - Filesystem object to use for opening the file. If nothing is - specified, an `AbstractFileSystem` object will be inferred. - engine : str, default "auto" - Parquet engine to use for metadata parsing. Allowed options - include "fastparquet", "pyarrow", and "auto". The specified - engine must be installed in the current environment. If - "auto" is specified, and both engines are installed, - "fastparquet" will take precedence over "pyarrow". - columns: list, optional - List of all column names that may be read from the file. - row_groups : list, optional - List of all row-groups that may be read from the file. This - may be a list of row-group indices (integers), or it may be - a list of `RowGroup` metadata objects (if the "fastparquet" - engine is used). - storage_options : dict, optional - Used to generate an `AbstractFileSystem` object if `fs` was - not specified. - max_gap : int, optional - Neighboring byte ranges will only be merged when their - inter-range gap is <= `max_gap`. Default is 64KB. - max_block : int, optional - Neighboring byte ranges will only be merged when the size of - the aggregated range is <= `max_block`. Default is 256MB. - footer_sample_size : int, optional - Number of bytes to read from the end of the path to look - for the footer metadata. If the sampled bytes do not contain - the footer, a second read request will be required, and - performance will suffer. Default is 1MB. - filters : list[list], optional - List of filters to apply to prevent reading row groups, of the - same format as accepted by the loading engines. Ignored if - ``row_groups`` is specified. - **kwargs : - Optional key-word arguments to pass to `fs.open` - """ - - # Make sure we have an `AbstractFileSystem` object - # to work with - if fs is None: - path0 = path - if isinstance(path, (list, tuple)): - path = path[0] - fs, path = url_to_fs(path, **(storage_options or {})) - else: - path0 = path - - # For now, `columns == []` not supported, is the same - # as all columns - if columns is not None and len(columns) == 0: - columns = None - - # Set the engine - engine = _set_engine(engine) - - if isinstance(path0, (list, tuple)): - paths = path0 - elif "*" in path: - paths = fs.glob(path) - elif path0.endswith("/"): # or fs.isdir(path): - paths = [ - _ - for _ in fs.find(path, withdirs=False, detail=False) - if _.endswith((".parquet", ".parq")) - ] - else: - paths = [path] - - data = _get_parquet_byte_ranges( - paths, - fs, - metadata=metadata, - columns=columns, - row_groups=row_groups, - engine=engine, - max_gap=max_gap, - max_block=max_block, - footer_sample_size=footer_sample_size, - filters=filters, - ) - - # Call self.open with "parts" caching - options = kwargs.pop("cache_options", {}).copy() - return [ - AlreadyBufferedFile( - fs=None, - path=fn, - mode="rb", - cache_type="parts", - cache_options={ - **options, - "data": ranges, - }, - size=max(_[1] for _ in ranges), - **kwargs, - ) - for fn, ranges in data.items() - ] - - -def open_parquet_file(*args, **kwargs): - """Create files tailed to reading specific parts of parquet files - - Please see ``open_parquet_files`` for details of the arguments. The - difference is, this function always returns a single ``AleadyBufferedFile``, - whereas `open_parquet_files`` always returns a list of files, even if - there are one or zero matching parquet files. - """ - return open_parquet_files(*args, **kwargs)[0] - - -def _get_parquet_byte_ranges( - paths, - fs, - metadata=None, - columns=None, - row_groups=None, - max_gap=64_000, - max_block=256_000_000, - footer_sample_size=1_000_000, - engine="auto", - filters=None, -): - """Get a dictionary of the known byte ranges needed - to read a specific column/row-group selection from a - Parquet dataset. Each value in the output dictionary - is intended for use as the `data` argument for the - `KnownPartsOfAFile` caching strategy of a single path. - """ - - # Set engine if necessary - if isinstance(engine, str): - engine = _set_engine(engine) - - # Pass to a specialized function if metadata is defined - if metadata is not None: - # Use the provided parquet metadata object - # to avoid transferring/parsing footer metadata - return _get_parquet_byte_ranges_from_metadata( - metadata, - fs, - engine, - columns=columns, - row_groups=row_groups, - max_gap=max_gap, - max_block=max_block, - filters=filters, - ) - - # Populate global paths, starts, & ends - if columns is None and row_groups is None and filters is None: - # We are NOT selecting specific columns or row-groups. - # - # We can avoid sampling the footers, and just transfer - # all file data with cat_ranges - result = {path: {(0, len(data)): data} for path, data in fs.cat(paths).items()} - else: - # We ARE selecting specific columns or row-groups. - # - # Get file sizes asynchronously - file_sizes = fs.sizes(paths) - data_paths = [] - data_starts = [] - data_ends = [] - # Gather file footers. - # We just take the last `footer_sample_size` bytes of each - # file (or the entire file if it is smaller than that) - footer_starts = [ - max(0, file_size - footer_sample_size) for file_size in file_sizes - ] - footer_samples = fs.cat_ranges(paths, footer_starts, file_sizes) - - # Check our footer samples and re-sample if necessary. - large_footer = [] - for i, path in enumerate(paths): - footer_size = int.from_bytes(footer_samples[i][-8:-4], "little") - real_footer_start = file_sizes[i] - (footer_size + 8) - if real_footer_start < footer_starts[i]: - large_footer.append((i, real_footer_start)) - if large_footer: - warnings.warn( - f"Not enough data was used to sample the parquet footer. " - f"Try setting footer_sample_size >= {large_footer}." - ) - path0 = [paths[i] for i, _ in large_footer] - starts = [_[1] for _ in large_footer] - ends = [file_sizes[i] - footer_sample_size for i, _ in large_footer] - data = fs.cat_ranges(path0, starts, ends) - for i, (path, start, block) in enumerate(zip(path0, starts, data)): - footer_samples[i] = block + footer_samples[i] - footer_starts[i] = start - result = { - path: {(start, size): data} - for path, start, size, data in zip( - paths, footer_starts, file_sizes, footer_samples - ) - } - - # Calculate required byte ranges for each path - for i, path in enumerate(paths): - # Use "engine" to collect data byte ranges - path_data_starts, path_data_ends = engine._parquet_byte_ranges( - columns, - row_groups=row_groups, - footer=footer_samples[i], - footer_start=footer_starts[i], - filters=filters, - ) - - data_paths += [path] * len(path_data_starts) - data_starts += path_data_starts - data_ends += path_data_ends - - # Merge adjacent offset ranges - data_paths, data_starts, data_ends = merge_offset_ranges( - data_paths, - data_starts, - data_ends, - max_gap=max_gap, - max_block=max_block, - sort=True, - ) - - # Transfer the data byte-ranges into local memory - _transfer_ranges(fs, result, data_paths, data_starts, data_ends) - - # Add b"PAR1" to headers - _add_header_magic(result) - - return result - - -def _get_parquet_byte_ranges_from_metadata( - metadata, - fs, - engine, - columns=None, - row_groups=None, - max_gap=64_000, - max_block=256_000_000, - filters=None, -): - """Simplified version of `_get_parquet_byte_ranges` for - the case that an engine-specific `metadata` object is - provided, and the remote footer metadata does not need to - be transferred before calculating the required byte ranges. - """ - - # Use "engine" to collect data byte ranges - data_paths, data_starts, data_ends = engine._parquet_byte_ranges( - columns, row_groups=row_groups, metadata=metadata, filters=filters - ) - - # Merge adjacent offset ranges - data_paths, data_starts, data_ends = merge_offset_ranges( - data_paths, - data_starts, - data_ends, - max_gap=max_gap, - max_block=max_block, - sort=False, # Should be sorted - ) - - # Transfer the data byte-ranges into local memory - result = {fn: {} for fn in list(set(data_paths))} - _transfer_ranges(fs, result, data_paths, data_starts, data_ends) - - # Add b"PAR1" to header - _add_header_magic(result) - - return result - - -def _transfer_ranges(fs, blocks, paths, starts, ends): - # Use cat_ranges to gather the data byte_ranges - ranges = (paths, starts, ends) - for path, start, stop, data in zip(*ranges, fs.cat_ranges(*ranges)): - blocks[path][(start, stop)] = data - - -def _add_header_magic(data): - # Add b"PAR1" to file headers - for path in list(data): - add_magic = True - for k in data[path]: - if k[0] == 0 and k[1] >= 4: - add_magic = False - break - if add_magic: - data[path][(0, 4)] = b"PAR1" - - -def _set_engine(engine_str): - # Define a list of parquet engines to try - if engine_str == "auto": - try_engines = ("fastparquet", "pyarrow") - elif not isinstance(engine_str, str): - raise ValueError( - "Failed to set parquet engine! " - "Please pass 'fastparquet', 'pyarrow', or 'auto'" - ) - elif engine_str not in ("fastparquet", "pyarrow"): - raise ValueError(f"{engine_str} engine not supported by `fsspec.parquet`") - else: - try_engines = [engine_str] - - # Try importing the engines in `try_engines`, - # and choose the first one that succeeds - for engine in try_engines: - try: - if engine == "fastparquet": - return FastparquetEngine() - elif engine == "pyarrow": - return PyarrowEngine() - except ImportError: - pass - - # Raise an error if a supported parquet engine - # was not found - raise ImportError( - f"The following parquet engines are not installed " - f"in your python environment: {try_engines}." - f"Please install 'fastparquert' or 'pyarrow' to " - f"utilize the `fsspec.parquet` module." - ) - - -class FastparquetEngine: - # The purpose of the FastparquetEngine class is - # to check if fastparquet can be imported (on initialization) - # and to define a `_parquet_byte_ranges` method. In the - # future, this class may also be used to define other - # methods/logic that are specific to fastparquet. - - def __init__(self): - import fastparquet as fp - - self.fp = fp - - def _parquet_byte_ranges( - self, - columns, - row_groups=None, - metadata=None, - footer=None, - footer_start=None, - filters=None, - ): - # Initialize offset ranges and define ParqetFile metadata - pf = metadata - data_paths, data_starts, data_ends = [], [], [] - if filters and row_groups: - raise ValueError("filters and row_groups cannot be used together") - if pf is None: - pf = self.fp.ParquetFile(io.BytesIO(footer)) - - # Convert columns to a set and add any index columns - # specified in the pandas metadata (just in case) - column_set = None if columns is None else {c.split(".", 1)[0] for c in columns} - if column_set is not None and hasattr(pf, "pandas_metadata"): - md_index = [ - ind - for ind in pf.pandas_metadata.get("index_columns", []) - # Ignore RangeIndex information - if not isinstance(ind, dict) - ] - column_set |= set(md_index) - - # Check if row_groups is a list of integers - # or a list of row-group metadata - if filters: - from fastparquet.api import filter_row_groups - - row_group_indices = None - row_groups = filter_row_groups(pf, filters) - elif row_groups and not isinstance(row_groups[0], int): - # Input row_groups contains row-group metadata - row_group_indices = None - else: - # Input row_groups contains row-group indices - row_group_indices = row_groups - row_groups = pf.row_groups - if column_set is not None: - column_set = [ - _ if isinstance(_, list) else _.split(".") for _ in column_set - ] - - # Loop through column chunks to add required byte ranges - for r, row_group in enumerate(row_groups): - # Skip this row-group if we are targeting - # specific row-groups - if row_group_indices is None or r in row_group_indices: - # Find the target parquet-file path for `row_group` - fn = pf.row_group_filename(row_group) - - for column in row_group.columns: - name = column.meta_data.path_in_schema - # Skip this column if we are targeting specific columns - if column_set is None or _cmp(name, column_set): - file_offset0 = column.meta_data.dictionary_page_offset - if file_offset0 is None: - file_offset0 = column.meta_data.data_page_offset - num_bytes = column.meta_data.total_compressed_size - if footer_start is None or file_offset0 < footer_start: - data_paths.append(fn) - data_starts.append(file_offset0) - data_ends.append( - min( - file_offset0 + num_bytes, - footer_start or (file_offset0 + num_bytes), - ) - ) - - if metadata: - # The metadata in this call may map to multiple - # file paths. Need to include `data_paths` - return data_paths, data_starts, data_ends - return data_starts, data_ends - - -class PyarrowEngine: - # The purpose of the PyarrowEngine class is - # to check if pyarrow can be imported (on initialization) - # and to define a `_parquet_byte_ranges` method. In the - # future, this class may also be used to define other - # methods/logic that are specific to pyarrow. - - def __init__(self): - import pyarrow.parquet as pq - - self.pq = pq - - def _parquet_byte_ranges( - self, - columns, - row_groups=None, - metadata=None, - footer=None, - footer_start=None, - filters=None, - ): - if metadata is not None: - raise ValueError("metadata input not supported for PyarrowEngine") - if filters: - # there must be a way! - raise NotImplementedError - - data_starts, data_ends = [], [] - md = self.pq.ParquetFile(io.BytesIO(footer)).metadata - - # Convert columns to a set and add any index columns - # specified in the pandas metadata (just in case) - column_set = None if columns is None else set(columns) - if column_set is not None: - schema = md.schema.to_arrow_schema() - has_pandas_metadata = ( - schema.metadata is not None and b"pandas" in schema.metadata - ) - if has_pandas_metadata: - md_index = [ - ind - for ind in json.loads( - schema.metadata[b"pandas"].decode("utf8") - ).get("index_columns", []) - # Ignore RangeIndex information - if not isinstance(ind, dict) - ] - column_set |= set(md_index) - if column_set is not None: - column_set = [ - _[:1] if isinstance(_, list) else _.split(".")[:1] for _ in column_set - ] - - # Loop through column chunks to add required byte ranges - for r in range(md.num_row_groups): - # Skip this row-group if we are targeting - # specific row-groups - if row_groups is None or r in row_groups: - row_group = md.row_group(r) - for c in range(row_group.num_columns): - column = row_group.column(c) - name = column.path_in_schema.split(".") - # Skip this column if we are targeting specific columns - if column_set is None or _cmp(name, column_set): - meta = column.to_dict() - # Any offset could be the first one - file_offset0 = min( - _ - for _ in [ - meta.get("dictionary_page_offset"), - meta.get("data_page_offset"), - meta.get("index_page_offset"), - ] - if _ is not None - ) - if file_offset0 < footer_start: - data_starts.append(file_offset0) - data_ends.append( - min( - meta["total_compressed_size"] + file_offset0, - footer_start, - ) - ) - - data_starts.append(footer_start) - data_ends.append(footer_start + len(footer)) - return data_starts, data_ends - - -def _cmp(name, column_set): - return any(all(a == b for a, b in zip(name, _)) for _ in column_set) diff --git a/venv/lib/python3.10/site-packages/fsspec/registry.py b/venv/lib/python3.10/site-packages/fsspec/registry.py deleted file mode 100644 index 597c6ba57a7cb70c65fd6daeb97ce7ab703a5121..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/registry.py +++ /dev/null @@ -1,333 +0,0 @@ -from __future__ import annotations - -import importlib -import types -import warnings - -__all__ = ["registry", "get_filesystem_class", "default"] - -# internal, mutable -_registry: dict[str, type] = {} - -# external, immutable -registry = types.MappingProxyType(_registry) -default = "file" - - -def register_implementation(name, cls, clobber=False, errtxt=None): - """Add implementation class to the registry - - Parameters - ---------- - name: str - Protocol name to associate with the class - cls: class or str - if a class: fsspec-compliant implementation class (normally inherits from - ``fsspec.AbstractFileSystem``, gets added straight to the registry. If a - str, the full path to an implementation class like package.module.class, - which gets added to known_implementations, - so the import is deferred until the filesystem is actually used. - clobber: bool (optional) - Whether to overwrite a protocol with the same name; if False, will raise - instead. - errtxt: str (optional) - If given, then a failure to import the given class will result in this - text being given. - """ - if isinstance(cls, str): - if name in known_implementations and clobber is False: - if cls != known_implementations[name]["class"]: - raise ValueError( - f"Name ({name}) already in the known_implementations and clobber " - f"is False" - ) - else: - known_implementations[name] = { - "class": cls, - "err": errtxt or f"{cls} import failed for protocol {name}", - } - - else: - if name in registry and clobber is False: - if _registry[name] is not cls: - raise ValueError( - f"Name ({name}) already in the registry and clobber is False" - ) - else: - _registry[name] = cls - - -# protocols mapped to the class which implements them. This dict can be -# updated with register_implementation -known_implementations = { - "abfs": { - "class": "adlfs.AzureBlobFileSystem", - "err": "Install adlfs to access Azure Datalake Gen2 and Azure Blob Storage", - }, - "adl": { - "class": "adlfs.AzureDatalakeFileSystem", - "err": "Install adlfs to access Azure Datalake Gen1", - }, - "arrow_hdfs": { - "class": "fsspec.implementations.arrow.HadoopFileSystem", - "err": "pyarrow and local java libraries required for HDFS", - }, - "async_wrapper": { - "class": "fsspec.implementations.asyn_wrapper.AsyncFileSystemWrapper", - }, - "asynclocal": { - "class": "morefs.asyn_local.AsyncLocalFileSystem", - "err": "Install 'morefs[asynclocalfs]' to use AsyncLocalFileSystem", - }, - "asyncwrapper": { - "class": "fsspec.implementations.asyn_wrapper.AsyncFileSystemWrapper", - }, - "az": { - "class": "adlfs.AzureBlobFileSystem", - "err": "Install adlfs to access Azure Datalake Gen2 and Azure Blob Storage", - }, - "blockcache": {"class": "fsspec.implementations.cached.CachingFileSystem"}, - "box": { - "class": "boxfs.BoxFileSystem", - "err": "Please install boxfs to access BoxFileSystem", - }, - "cached": {"class": "fsspec.implementations.cached.CachingFileSystem"}, - "dask": { - "class": "fsspec.implementations.dask.DaskWorkerFileSystem", - "err": "Install dask distributed to access worker file system", - }, - "data": {"class": "fsspec.implementations.data.DataFileSystem"}, - "dbfs": { - "class": "fsspec.implementations.dbfs.DatabricksFileSystem", - "err": "Install the requests package to use the DatabricksFileSystem", - }, - "dir": {"class": "fsspec.implementations.dirfs.DirFileSystem"}, - "dropbox": { - "class": "dropboxdrivefs.DropboxDriveFileSystem", - "err": ( - 'DropboxFileSystem requires "dropboxdrivefs","requests" and "' - '"dropbox" to be installed' - ), - }, - "dvc": { - "class": "dvc.api.DVCFileSystem", - "err": "Install dvc to access DVCFileSystem", - }, - "file": {"class": "fsspec.implementations.local.LocalFileSystem"}, - "filecache": {"class": "fsspec.implementations.cached.WholeFileCacheFileSystem"}, - "ftp": {"class": "fsspec.implementations.ftp.FTPFileSystem"}, - "gcs": { - "class": "gcsfs.GCSFileSystem", - "err": "Please install gcsfs to access Google Storage", - }, - "gdrive": { - "class": "gdrive_fsspec.GoogleDriveFileSystem", - "err": "Please install gdrive_fs for access to Google Drive", - }, - "generic": {"class": "fsspec.generic.GenericFileSystem"}, - "gist": { - "class": "fsspec.implementations.gist.GistFileSystem", - "err": "Install the requests package to use the gist FS", - }, - "git": { - "class": "fsspec.implementations.git.GitFileSystem", - "err": "Install pygit2 to browse local git repos", - }, - "github": { - "class": "fsspec.implementations.github.GithubFileSystem", - "err": "Install the requests package to use the github FS", - }, - "gs": { - "class": "gcsfs.GCSFileSystem", - "err": "Please install gcsfs to access Google Storage", - }, - "hdfs": { - "class": "fsspec.implementations.arrow.HadoopFileSystem", - "err": "pyarrow and local java libraries required for HDFS", - }, - "hf": { - "class": "huggingface_hub.HfFileSystem", - "err": "Install huggingface_hub to access HfFileSystem", - }, - "http": { - "class": "fsspec.implementations.http.HTTPFileSystem", - "err": 'HTTPFileSystem requires "requests" and "aiohttp" to be installed', - }, - "https": { - "class": "fsspec.implementations.http.HTTPFileSystem", - "err": 'HTTPFileSystem requires "requests" and "aiohttp" to be installed', - }, - "jlab": { - "class": "fsspec.implementations.jupyter.JupyterFileSystem", - "err": "Jupyter FS requires requests to be installed", - }, - "jupyter": { - "class": "fsspec.implementations.jupyter.JupyterFileSystem", - "err": "Jupyter FS requires requests to be installed", - }, - "lakefs": { - "class": "lakefs_spec.LakeFSFileSystem", - "err": "Please install lakefs-spec to access LakeFSFileSystem", - }, - "libarchive": { - "class": "fsspec.implementations.libarchive.LibArchiveFileSystem", - "err": "LibArchive requires to be installed", - }, - "local": {"class": "fsspec.implementations.local.LocalFileSystem"}, - "memory": {"class": "fsspec.implementations.memory.MemoryFileSystem"}, - "oci": { - "class": "ocifs.OCIFileSystem", - "err": "Install ocifs to access OCI Object Storage", - }, - "ocilake": { - "class": "ocifs.OCIFileSystem", - "err": "Install ocifs to access OCI Data Lake", - }, - "oss": { - "class": "ossfs.OSSFileSystem", - "err": "Install ossfs to access Alibaba Object Storage System", - }, - "pyscript": { - "class": "pyscript_fsspec_client.client.PyscriptFileSystem", - "err": "This only runs in a pyscript context", - }, - "reference": {"class": "fsspec.implementations.reference.ReferenceFileSystem"}, - "root": { - "class": "fsspec_xrootd.XRootDFileSystem", - "err": ( - "Install fsspec-xrootd to access xrootd storage system. " - "Note: 'root' is the protocol name for xrootd storage systems, " - "not referring to root directories" - ), - }, - "s3": {"class": "s3fs.S3FileSystem", "err": "Install s3fs to access S3"}, - "s3a": {"class": "s3fs.S3FileSystem", "err": "Install s3fs to access S3"}, - "sftp": { - "class": "fsspec.implementations.sftp.SFTPFileSystem", - "err": 'SFTPFileSystem requires "paramiko" to be installed', - }, - "simplecache": {"class": "fsspec.implementations.cached.SimpleCacheFileSystem"}, - "smb": { - "class": "fsspec.implementations.smb.SMBFileSystem", - "err": 'SMB requires "smbprotocol" or "smbprotocol[kerberos]" installed', - }, - "ssh": { - "class": "fsspec.implementations.sftp.SFTPFileSystem", - "err": 'SFTPFileSystem requires "paramiko" to be installed', - }, - "tar": {"class": "fsspec.implementations.tar.TarFileSystem"}, - "tos": { - "class": "tosfs.TosFileSystem", - "err": "Install tosfs to access ByteDance volcano engine Tinder Object Storage", - }, - "tosfs": { - "class": "tosfs.TosFileSystem", - "err": "Install tosfs to access ByteDance volcano engine Tinder Object Storage", - }, - "wandb": {"class": "wandbfs.WandbFS", "err": "Install wandbfs to access wandb"}, - "webdav": { - "class": "webdav4.fsspec.WebdavFileSystem", - "err": "Install webdav4 to access WebDAV", - }, - "webhdfs": { - "class": "fsspec.implementations.webhdfs.WebHDFS", - "err": 'webHDFS access requires "requests" to be installed', - }, - "zip": {"class": "fsspec.implementations.zip.ZipFileSystem"}, -} - -assert list(known_implementations) == sorted(known_implementations), ( - "Not in alphabetical order" -) - - -def get_filesystem_class(protocol): - """Fetch named protocol implementation from the registry - - The dict ``known_implementations`` maps protocol names to the locations - of classes implementing the corresponding file-system. When used for the - first time, appropriate imports will happen and the class will be placed in - the registry. All subsequent calls will fetch directly from the registry. - - Some protocol implementations require additional dependencies, and so the - import may fail. In this case, the string in the "err" field of the - ``known_implementations`` will be given as the error message. - """ - if not protocol: - protocol = default - - if protocol not in registry: - if protocol not in known_implementations: - raise ValueError(f"Protocol not known: {protocol}") - bit = known_implementations[protocol] - try: - register_implementation(protocol, _import_class(bit["class"])) - except ImportError as e: - raise ImportError(bit.get("err")) from e - cls = registry[protocol] - if getattr(cls, "protocol", None) in ("abstract", None): - cls.protocol = protocol - - return cls - - -s3_msg = """Your installed version of s3fs is very old and known to cause -severe performance issues, see also https://github.com/dask/dask/issues/10276 - -To fix, you should specify a lower version bound on s3fs, or -update the current installation. -""" - - -def _import_class(fqp: str): - """Take a fully-qualified path and return the imported class or identifier. - - ``fqp`` is of the form "package.module.klass" or - "package.module:subobject.klass". - - Warnings - -------- - This can import arbitrary modules. Make sure you haven't installed any modules - that may execute malicious code at import time. - """ - if ":" in fqp: - mod, name = fqp.rsplit(":", 1) - else: - mod, name = fqp.rsplit(".", 1) - - is_s3 = mod == "s3fs" - mod = importlib.import_module(mod) - if is_s3 and mod.__version__.split(".") < ["0", "5"]: - warnings.warn(s3_msg) - for part in name.split("."): - mod = getattr(mod, part) - - if not isinstance(mod, type): - raise TypeError(f"{fqp} is not a class") - - return mod - - -def filesystem(protocol, **storage_options): - """Instantiate filesystems for given protocol and arguments - - ``storage_options`` are specific to the protocol being chosen, and are - passed directly to the class. - """ - if protocol == "arrow_hdfs": - warnings.warn( - "The 'arrow_hdfs' protocol has been deprecated and will be " - "removed in the future. Specify it as 'hdfs'.", - DeprecationWarning, - ) - - cls = get_filesystem_class(protocol) - return cls(**storage_options) - - -def available_protocols(): - """Return a list of the implemented protocols. - - Note that any given protocol may require extra packages to be importable. - """ - return list(known_implementations) diff --git a/venv/lib/python3.10/site-packages/fsspec/spec.py b/venv/lib/python3.10/site-packages/fsspec/spec.py deleted file mode 100644 index b67d5c16fcdf09ce6f9e1354727196042cde3c4c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/spec.py +++ /dev/null @@ -1,2281 +0,0 @@ -from __future__ import annotations - -import io -import json -import logging -import os -import threading -import warnings -import weakref -from errno import ESPIPE -from glob import has_magic -from hashlib import sha256 -from typing import Any, ClassVar - -from .callbacks import DEFAULT_CALLBACK -from .config import apply_config, conf -from .dircache import DirCache -from .transaction import Transaction -from .utils import ( - _unstrip_protocol, - glob_translate, - isfilelike, - other_paths, - read_block, - stringify_path, - tokenize, -) - -logger = logging.getLogger("fsspec") - - -def make_instance(cls, args, kwargs): - return cls(*args, **kwargs) - - -class _Cached(type): - """ - Metaclass for caching file system instances. - - Notes - ----- - Instances are cached according to - - * The values of the class attributes listed in `_extra_tokenize_attributes` - * The arguments passed to ``__init__``. - - This creates an additional reference to the filesystem, which prevents the - filesystem from being garbage collected when all *user* references go away. - A call to the :meth:`AbstractFileSystem.clear_instance_cache` must *also* - be made for a filesystem instance to be garbage collected. - """ - - def __init__(cls, *args, **kwargs): - super().__init__(*args, **kwargs) - # Note: we intentionally create a reference here, to avoid garbage - # collecting instances when all other references are gone. To really - # delete a FileSystem, the cache must be cleared. - if conf.get("weakref_instance_cache"): # pragma: no cover - # debug option for analysing fork/spawn conditions - cls._cache = weakref.WeakValueDictionary() - else: - cls._cache = {} - cls._pid = os.getpid() - - def __call__(cls, *args, **kwargs): - kwargs = apply_config(cls, kwargs) - extra_tokens = tuple( - getattr(cls, attr, None) for attr in cls._extra_tokenize_attributes - ) - strip_tokenize_options = { - k: kwargs.pop(k) for k in cls._strip_tokenize_options if k in kwargs - } - token = tokenize( - cls, cls._pid, threading.get_ident(), *args, *extra_tokens, **kwargs - ) - skip = kwargs.pop("skip_instance_cache", False) - if os.getpid() != cls._pid: - cls._cache.clear() - cls._pid = os.getpid() - if not skip and cls.cachable and token in cls._cache: - cls._latest = token - return cls._cache[token] - else: - obj = super().__call__(*args, **kwargs, **strip_tokenize_options) - # Setting _fs_token here causes some static linters to complain. - obj._fs_token_ = token - obj.storage_args = args - obj.storage_options = kwargs - if obj.async_impl and obj.mirror_sync_methods: - from .asyn import mirror_sync_methods - - mirror_sync_methods(obj) - - if cls.cachable and not skip: - cls._latest = token - cls._cache[token] = obj - return obj - - -class AbstractFileSystem(metaclass=_Cached): - """ - An abstract super-class for pythonic file-systems - - Implementations are expected to be compatible with or, better, subclass - from here. - """ - - cachable = True # this class can be cached, instances reused - _cached = False - blocksize = 2**22 - sep = "/" - protocol: ClassVar[str | tuple[str, ...]] = "abstract" - _latest = None - async_impl = False - mirror_sync_methods = False - root_marker = "" # For some FSs, may require leading '/' or other character - transaction_type = Transaction - - #: Extra *class attributes* that should be considered when hashing. - _extra_tokenize_attributes = () - #: *storage options* that should not be considered when hashing. - _strip_tokenize_options = () - - # Set by _Cached metaclass - storage_args: tuple[Any, ...] - storage_options: dict[str, Any] - - def __init__(self, *args, **storage_options): - """Create and configure file-system instance - - Instances may be cachable, so if similar enough arguments are seen - a new instance is not required. The token attribute exists to allow - implementations to cache instances if they wish. - - A reasonable default should be provided if there are no arguments. - - Subclasses should call this method. - - Parameters - ---------- - use_listings_cache, listings_expiry_time, max_paths: - passed to ``DirCache``, if the implementation supports - directory listing caching. Pass use_listings_cache=False - to disable such caching. - skip_instance_cache: bool - If this is a cachable implementation, pass True here to force - creating a new instance even if a matching instance exists, and prevent - storing this instance. - asynchronous: bool - loop: asyncio-compatible IOLoop or None - """ - if self._cached: - # reusing instance, don't change - return - self._cached = True - self._intrans = False - self._transaction = None - self._invalidated_caches_in_transaction = [] - self.dircache = DirCache(**storage_options) - - if storage_options.pop("add_docs", None): - warnings.warn("add_docs is no longer supported.", FutureWarning) - - if storage_options.pop("add_aliases", None): - warnings.warn("add_aliases has been removed.", FutureWarning) - # This is set in _Cached - self._fs_token_ = None - - @property - def fsid(self): - """Persistent filesystem id that can be used to compare filesystems - across sessions. - """ - raise NotImplementedError - - @property - def _fs_token(self): - return self._fs_token_ - - def __dask_tokenize__(self): - return self._fs_token - - def __hash__(self): - return int(self._fs_token, 16) - - def __eq__(self, other): - return isinstance(other, type(self)) and self._fs_token == other._fs_token - - def __reduce__(self): - return make_instance, (type(self), self.storage_args, self.storage_options) - - @classmethod - def _strip_protocol(cls, path): - """Turn path from fully-qualified to file-system-specific - - May require FS-specific handling, e.g., for relative paths or links. - """ - if isinstance(path, list): - return [cls._strip_protocol(p) for p in path] - path = stringify_path(path) - protos = (cls.protocol,) if isinstance(cls.protocol, str) else cls.protocol - for protocol in protos: - if path.startswith(protocol + "://"): - path = path[len(protocol) + 3 :] - elif path.startswith(protocol + "::"): - path = path[len(protocol) + 2 :] - path = path.rstrip("/") - # use of root_marker to make minimum required path, e.g., "/" - return path or cls.root_marker - - def unstrip_protocol(self, name: str) -> str: - """Format FS-specific path to generic, including protocol""" - protos = (self.protocol,) if isinstance(self.protocol, str) else self.protocol - for protocol in protos: - if name.startswith(f"{protocol}://"): - return name - return f"{protos[0]}://{name}" - - @staticmethod - def _get_kwargs_from_urls(path): - """If kwargs can be encoded in the paths, extract them here - - This should happen before instantiation of the class; incoming paths - then should be amended to strip the options in methods. - - Examples may look like an sftp path "sftp://user@host:/my/path", where - the user and host should become kwargs and later get stripped. - """ - # by default, nothing happens - return {} - - @classmethod - def current(cls): - """Return the most recently instantiated FileSystem - - If no instance has been created, then create one with defaults - """ - if cls._latest in cls._cache: - return cls._cache[cls._latest] - return cls() - - @property - def transaction(self): - """A context within which files are committed together upon exit - - Requires the file class to implement `.commit()` and `.discard()` - for the normal and exception cases. - """ - if self._transaction is None: - self._transaction = self.transaction_type(self) - return self._transaction - - def start_transaction(self): - """Begin write transaction for deferring files, non-context version""" - self._intrans = True - self._transaction = self.transaction_type(self) - return self.transaction - - def end_transaction(self): - """Finish write transaction, non-context version""" - self.transaction.complete() - self._transaction = None - # The invalid cache must be cleared after the transaction is completed. - for path in self._invalidated_caches_in_transaction: - self.invalidate_cache(path) - self._invalidated_caches_in_transaction.clear() - - def invalidate_cache(self, path=None): - """ - Discard any cached directory information - - Parameters - ---------- - path: string or None - If None, clear all listings cached else listings at or under given - path. - """ - # Not necessary to implement invalidation mechanism, may have no cache. - # But if have, you should call this method of parent class from your - # subclass to ensure expiring caches after transacations correctly. - # See the implementation of FTPFileSystem in ftp.py - if self._intrans: - self._invalidated_caches_in_transaction.append(path) - - def mkdir(self, path, create_parents=True, **kwargs): - """ - Create directory entry at path - - For systems that don't have true directories, may create an for - this instance only and not touch the real filesystem - - Parameters - ---------- - path: str - location - create_parents: bool - if True, this is equivalent to ``makedirs`` - kwargs: - may be permissions, etc. - """ - pass # not necessary to implement, may not have directories - - def makedirs(self, path, exist_ok=False): - """Recursively make directories - - Creates directory at path and any intervening required directories. - Raises exception if, for instance, the path already exists but is a - file. - - Parameters - ---------- - path: str - leaf directory name - exist_ok: bool (False) - If False, will error if the target already exists - """ - pass # not necessary to implement, may not have directories - - def rmdir(self, path): - """Remove a directory, if empty""" - pass # not necessary to implement, may not have directories - - def ls(self, path, detail=True, **kwargs): - """List objects at path. - - This should include subdirectories and files at that location. The - difference between a file and a directory must be clear when details - are requested. - - The specific keys, or perhaps a FileInfo class, or similar, is TBD, - but must be consistent across implementations. - Must include: - - - full path to the entry (without protocol) - - size of the entry, in bytes. If the value cannot be determined, will - be ``None``. - - type of entry, "file", "directory" or other - - Additional information - may be present, appropriate to the file-system, e.g., generation, - checksum, etc. - - May use refresh=True|False to allow use of self._ls_from_cache to - check for a saved listing and avoid calling the backend. This would be - common where listing may be expensive. - - Parameters - ---------- - path: str - detail: bool - if True, gives a list of dictionaries, where each is the same as - the result of ``info(path)``. If False, gives a list of paths - (str). - kwargs: may have additional backend-specific options, such as version - information - - Returns - ------- - List of strings if detail is False, or list of directory information - dicts if detail is True. - """ - raise NotImplementedError - - def _ls_from_cache(self, path): - """Check cache for listing - - Returns listing, if found (may be empty list for a directly that exists - but contains nothing), None if not in cache. - """ - parent = self._parent(path) - try: - return self.dircache[path.rstrip("/")] - except KeyError: - pass - try: - files = [ - f - for f in self.dircache[parent] - if f["name"] == path - or (f["name"] == path.rstrip("/") and f["type"] == "directory") - ] - if len(files) == 0: - # parent dir was listed but did not contain this file - raise FileNotFoundError(path) - return files - except KeyError: - pass - - def walk(self, path, maxdepth=None, topdown=True, on_error="omit", **kwargs): - """Return all files under the given path. - - List all files, recursing into subdirectories; output is iterator-style, - like ``os.walk()``. For a simple list of files, ``find()`` is available. - - When topdown is True, the caller can modify the dirnames list in-place (perhaps - using del or slice assignment), and walk() will - only recurse into the subdirectories whose names remain in dirnames; - this can be used to prune the search, impose a specific order of visiting, - or even to inform walk() about directories the caller creates or renames before - it resumes walk() again. - Modifying dirnames when topdown is False has no effect. (see os.walk) - - Note that the "files" outputted will include anything that is not - a directory, such as links. - - Parameters - ---------- - path: str - Root to recurse into - maxdepth: int - Maximum recursion depth. None means limitless, but not recommended - on link-based file-systems. - topdown: bool (True) - Whether to walk the directory tree from the top downwards or from - the bottom upwards. - on_error: "omit", "raise", a callable - if omit (default), path with exception will simply be empty; - If raise, an underlying exception will be raised; - if callable, it will be called with a single OSError instance as argument - kwargs: passed to ``ls`` - """ - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - - path = self._strip_protocol(path) - full_dirs = {} - dirs = {} - files = {} - - detail = kwargs.pop("detail", False) - try: - listing = self.ls(path, detail=True, **kwargs) - except (FileNotFoundError, OSError) as e: - if on_error == "raise": - raise - if callable(on_error): - on_error(e) - return - - for info in listing: - # each info name must be at least [path]/part , but here - # we check also for names like [path]/part/ - pathname = info["name"].rstrip("/") - name = pathname.rsplit("/", 1)[-1] - if info["type"] == "directory" and pathname != path: - # do not include "self" path - full_dirs[name] = pathname - dirs[name] = info - elif pathname == path: - # file-like with same name as give path - files[""] = info - else: - files[name] = info - - if not detail: - dirs = list(dirs) - files = list(files) - - if topdown: - # Yield before recursion if walking top down - yield path, dirs, files - - if maxdepth is not None: - maxdepth -= 1 - if maxdepth < 1: - if not topdown: - yield path, dirs, files - return - - for d in dirs: - yield from self.walk( - full_dirs[d], - maxdepth=maxdepth, - detail=detail, - topdown=topdown, - **kwargs, - ) - - if not topdown: - # Yield after recursion if walking bottom up - yield path, dirs, files - - def find(self, path, maxdepth=None, withdirs=False, detail=False, **kwargs): - """List all files below path. - - Like posix ``find`` command without conditions - - Parameters - ---------- - path : str - maxdepth: int or None - If not None, the maximum number of levels to descend - withdirs: bool - Whether to include directory paths in the output. This is True - when used by glob, but users usually only want files. - kwargs are passed to ``ls``. - """ - # TODO: allow equivalent of -name parameter - path = self._strip_protocol(path) - out = {} - - # Add the root directory if withdirs is requested - # This is needed for posix glob compliance - if withdirs and path != "" and self.isdir(path): - out[path] = self.info(path) - - for _, dirs, files in self.walk(path, maxdepth, detail=True, **kwargs): - if withdirs: - files.update(dirs) - out.update({info["name"]: info for name, info in files.items()}) - if not out and self.isfile(path): - # walk works on directories, but find should also return [path] - # when path happens to be a file - out[path] = {} - names = sorted(out) - if not detail: - return names - else: - return {name: out[name] for name in names} - - def du(self, path, total=True, maxdepth=None, withdirs=False, **kwargs): - """Space used by files and optionally directories within a path - - Directory size does not include the size of its contents. - - Parameters - ---------- - path: str - total: bool - Whether to sum all the file sizes - maxdepth: int or None - Maximum number of directory levels to descend, None for unlimited. - withdirs: bool - Whether to include directory paths in the output. - kwargs: passed to ``find`` - - Returns - ------- - Dict of {path: size} if total=False, or int otherwise, where numbers - refer to bytes used. - """ - sizes = {} - if withdirs and self.isdir(path): - # Include top-level directory in output - info = self.info(path) - sizes[info["name"]] = info["size"] - for f in self.find(path, maxdepth=maxdepth, withdirs=withdirs, **kwargs): - info = self.info(f) - sizes[info["name"]] = info["size"] - if total: - return sum(sizes.values()) - else: - return sizes - - def glob(self, path, maxdepth=None, **kwargs): - """Find files by glob-matching. - - Pattern matching capabilities for finding files that match the given pattern. - - Parameters - ---------- - path: str - The glob pattern to match against - maxdepth: int or None - Maximum depth for ``'**'`` patterns. Applied on the first ``'**'`` found. - Must be at least 1 if provided. - kwargs: - Additional arguments passed to ``find`` (e.g., detail=True) - - Returns - ------- - List of matched paths, or dict of paths and their info if detail=True - - Notes - ----- - Supported patterns: - - '*': Matches any sequence of characters within a single directory level - - ``'**'``: Matches any number of directory levels (must be an entire path component) - - '?': Matches exactly one character - - '[abc]': Matches any character in the set - - '[a-z]': Matches any character in the range - - '[!abc]': Matches any character NOT in the set - - Special behaviors: - - If the path ends with '/', only folders are returned - - Consecutive '*' characters are compressed into a single '*' - - Empty brackets '[]' never match anything - - Negated empty brackets '[!]' match any single character - - Special characters in character classes are escaped properly - - Limitations: - - ``'**'`` must be a complete path component (e.g., ``'a/**/b'``, not ``'a**b'``) - - No brace expansion ('{a,b}.txt') - - No extended glob patterns ('+(pattern)', '!(pattern)') - """ - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - - import re - - seps = (os.path.sep, os.path.altsep) if os.path.altsep else (os.path.sep,) - ends_with_sep = path.endswith(seps) # _strip_protocol strips trailing slash - path = self._strip_protocol(path) - append_slash_to_dirname = ends_with_sep or path.endswith( - tuple(sep + "**" for sep in seps) - ) - idx_star = path.find("*") if path.find("*") >= 0 else len(path) - idx_qmark = path.find("?") if path.find("?") >= 0 else len(path) - idx_brace = path.find("[") if path.find("[") >= 0 else len(path) - - min_idx = min(idx_star, idx_qmark, idx_brace) - - detail = kwargs.pop("detail", False) - - if not has_magic(path): - if self.exists(path, **kwargs): - if not detail: - return [path] - else: - return {path: self.info(path, **kwargs)} - else: - if not detail: - return [] # glob of non-existent returns empty - else: - return {} - elif "/" in path[:min_idx]: - min_idx = path[:min_idx].rindex("/") - root = path[: min_idx + 1] - depth = path[min_idx + 1 :].count("/") + 1 - else: - root = "" - depth = path[min_idx + 1 :].count("/") + 1 - - if "**" in path: - if maxdepth is not None: - idx_double_stars = path.find("**") - depth_double_stars = path[idx_double_stars:].count("/") + 1 - depth = depth - depth_double_stars + maxdepth - else: - depth = None - - allpaths = self.find(root, maxdepth=depth, withdirs=True, detail=True, **kwargs) - - pattern = glob_translate(path + ("/" if ends_with_sep else "")) - pattern = re.compile(pattern) - - out = { - p: info - for p, info in sorted(allpaths.items()) - if pattern.match( - p + "/" - if append_slash_to_dirname and info["type"] == "directory" - else p - ) - } - - if detail: - return out - else: - return list(out) - - def exists(self, path, **kwargs): - """Is there a file at the given path""" - try: - self.info(path, **kwargs) - return True - except: # noqa: E722 - # any exception allowed bar FileNotFoundError? - return False - - def lexists(self, path, **kwargs): - """If there is a file at the given path (including - broken links)""" - return self.exists(path) - - def info(self, path, **kwargs): - """Give details of entry at path - - Returns a single dictionary, with exactly the same information as ``ls`` - would with ``detail=True``. - - The default implementation calls ls and could be overridden by a - shortcut. kwargs are passed on to ```ls()``. - - Some file systems might not be able to measure the file's size, in - which case, the returned dict will include ``'size': None``. - - Returns - ------- - dict with keys: name (full path in the FS), size (in bytes), type (file, - directory, or something else) and other FS-specific keys. - """ - path = self._strip_protocol(path) - out = self.ls(self._parent(path), detail=True, **kwargs) - out = [o for o in out if o["name"].rstrip("/") == path] - if out: - return out[0] - out = self.ls(path, detail=True, **kwargs) - path = path.rstrip("/") - out1 = [o for o in out if o["name"].rstrip("/") == path] - if len(out1) == 1: - if "size" not in out1[0]: - out1[0]["size"] = None - return out1[0] - elif len(out1) > 1 or out: - return {"name": path, "size": 0, "type": "directory"} - else: - raise FileNotFoundError(path) - - def checksum(self, path): - """Unique value for current version of file - - If the checksum is the same from one moment to another, the contents - are guaranteed to be the same. If the checksum changes, the contents - *might* have changed. - - This should normally be overridden; default will probably capture - creation/modification timestamp (which would be good) or maybe - access timestamp (which would be bad) - """ - return int(tokenize(self.info(path)), 16) - - def size(self, path): - """Size in bytes of file""" - return self.info(path).get("size", None) - - def sizes(self, paths): - """Size in bytes of each file in a list of paths""" - return [self.size(p) for p in paths] - - def isdir(self, path): - """Is this entry directory-like?""" - try: - return self.info(path)["type"] == "directory" - except OSError: - return False - - def isfile(self, path): - """Is this entry file-like?""" - try: - return self.info(path)["type"] == "file" - except: # noqa: E722 - return False - - def read_text(self, path, encoding=None, errors=None, newline=None, **kwargs): - """Get the contents of the file as a string. - - Parameters - ---------- - path: str - URL of file on this filesystems - encoding, errors, newline: same as `open`. - """ - with self.open( - path, - mode="r", - encoding=encoding, - errors=errors, - newline=newline, - **kwargs, - ) as f: - return f.read() - - def write_text( - self, path, value, encoding=None, errors=None, newline=None, **kwargs - ): - """Write the text to the given file. - - An existing file will be overwritten. - - Parameters - ---------- - path: str - URL of file on this filesystems - value: str - Text to write. - encoding, errors, newline: same as `open`. - """ - with self.open( - path, - mode="w", - encoding=encoding, - errors=errors, - newline=newline, - **kwargs, - ) as f: - return f.write(value) - - def cat_file(self, path, start=None, end=None, **kwargs): - """Get the content of a file - - Parameters - ---------- - path: URL of file on this filesystems - start, end: int - Bytes limits of the read. If negative, backwards from end, - like usual python slices. Either can be None for start or - end of file, respectively - kwargs: passed to ``open()``. - """ - # explicitly set buffering off? - with self.open(path, "rb", **kwargs) as f: - if start is not None: - if start >= 0: - f.seek(start) - else: - f.seek(max(0, f.size + start)) - if end is not None: - if end < 0: - end = f.size + end - return f.read(end - f.tell()) - return f.read() - - def pipe_file(self, path, value, mode="overwrite", **kwargs): - """Set the bytes of given file""" - if mode == "create" and self.exists(path): - # non-atomic but simple way; or could use "xb" in open(), which is likely - # not as well supported - raise FileExistsError - with self.open(path, "wb", **kwargs) as f: - f.write(value) - - def pipe(self, path, value=None, **kwargs): - """Put value into path - - (counterpart to ``cat``) - - Parameters - ---------- - path: string or dict(str, bytes) - If a string, a single remote location to put ``value`` bytes; if a dict, - a mapping of {path: bytesvalue}. - value: bytes, optional - If using a single path, these are the bytes to put there. Ignored if - ``path`` is a dict - """ - if isinstance(path, str): - self.pipe_file(self._strip_protocol(path), value, **kwargs) - elif isinstance(path, dict): - for k, v in path.items(): - self.pipe_file(self._strip_protocol(k), v, **kwargs) - else: - raise ValueError("path must be str or dict") - - def cat_ranges( - self, paths, starts, ends, max_gap=None, on_error="return", **kwargs - ): - """Get the contents of byte ranges from one or more files - - Parameters - ---------- - paths: list - A list of of filepaths on this filesystems - starts, ends: int or list - Bytes limits of the read. If using a single int, the same value will be - used to read all the specified files. - """ - if max_gap is not None: - raise NotImplementedError - if not isinstance(paths, list): - raise TypeError - if not isinstance(starts, list): - starts = [starts] * len(paths) - if not isinstance(ends, list): - ends = [ends] * len(paths) - if len(starts) != len(paths) or len(ends) != len(paths): - raise ValueError - out = [] - for p, s, e in zip(paths, starts, ends): - try: - out.append(self.cat_file(p, s, e)) - except Exception as e: - if on_error == "return": - out.append(e) - else: - raise - return out - - def cat(self, path, recursive=False, on_error="raise", **kwargs): - """Fetch (potentially multiple) paths' contents - - Parameters - ---------- - recursive: bool - If True, assume the path(s) are directories, and get all the - contained files - on_error : "raise", "omit", "return" - If raise, an underlying exception will be raised (converted to KeyError - if the type is in self.missing_exceptions); if omit, keys with exception - will simply not be included in the output; if "return", all keys are - included in the output, but the value will be bytes or an exception - instance. - kwargs: passed to cat_file - - Returns - ------- - dict of {path: contents} if there are multiple paths - or the path has been otherwise expanded - """ - paths = self.expand_path(path, recursive=recursive, **kwargs) - if ( - len(paths) > 1 - or isinstance(path, list) - or paths[0] != self._strip_protocol(path) - ): - out = {} - for path in paths: - try: - out[path] = self.cat_file(path, **kwargs) - except Exception as e: - if on_error == "raise": - raise - if on_error == "return": - out[path] = e - return out - else: - return self.cat_file(paths[0], **kwargs) - - def get_file(self, rpath, lpath, callback=DEFAULT_CALLBACK, outfile=None, **kwargs): - """Copy single remote file to local""" - from .implementations.local import LocalFileSystem - - if isfilelike(lpath): - outfile = lpath - elif self.isdir(rpath): - os.makedirs(lpath, exist_ok=True) - return None - - fs = LocalFileSystem(auto_mkdir=True) - fs.makedirs(fs._parent(lpath), exist_ok=True) - - with self.open(rpath, "rb", **kwargs) as f1: - if outfile is None: - outfile = open(lpath, "wb") - - try: - callback.set_size(getattr(f1, "size", None)) - data = True - while data: - data = f1.read(self.blocksize) - segment_len = outfile.write(data) - if segment_len is None: - segment_len = len(data) - callback.relative_update(segment_len) - finally: - if not isfilelike(lpath): - outfile.close() - - def get( - self, - rpath, - lpath, - recursive=False, - callback=DEFAULT_CALLBACK, - maxdepth=None, - **kwargs, - ): - """Copy file(s) to local. - - Copies a specific file or tree of files (if recursive=True). If lpath - ends with a "/", it will be assumed to be a directory, and target files - will go within. Can submit a list of paths, which may be glob-patterns - and will be expanded. - - Calls get_file for each source. - """ - if isinstance(lpath, list) and isinstance(rpath, list): - # No need to expand paths when both source and destination - # are provided as lists - rpaths = rpath - lpaths = lpath - else: - from .implementations.local import ( - LocalFileSystem, - make_path_posix, - trailing_sep, - ) - - source_is_str = isinstance(rpath, str) - rpaths = self.expand_path( - rpath, recursive=recursive, maxdepth=maxdepth, **kwargs - ) - if source_is_str and (not recursive or maxdepth is not None): - # Non-recursive glob does not copy directories - rpaths = [p for p in rpaths if not (trailing_sep(p) or self.isdir(p))] - if not rpaths: - return - - if isinstance(lpath, str): - lpath = make_path_posix(lpath) - - source_is_file = len(rpaths) == 1 - dest_is_dir = isinstance(lpath, str) and ( - trailing_sep(lpath) or LocalFileSystem().isdir(lpath) - ) - - exists = source_is_str and ( - (has_magic(rpath) and source_is_file) - or (not has_magic(rpath) and dest_is_dir and not trailing_sep(rpath)) - ) - lpaths = other_paths( - rpaths, - lpath, - exists=exists, - flatten=not source_is_str, - ) - - callback.set_size(len(lpaths)) - for lpath, rpath in callback.wrap(zip(lpaths, rpaths)): - with callback.branched(rpath, lpath) as child: - self.get_file(rpath, lpath, callback=child, **kwargs) - - def put_file( - self, lpath, rpath, callback=DEFAULT_CALLBACK, mode="overwrite", **kwargs - ): - """Copy single file to remote""" - if mode == "create" and self.exists(rpath): - raise FileExistsError - if os.path.isdir(lpath): - self.makedirs(rpath, exist_ok=True) - return None - - with open(lpath, "rb") as f1: - size = f1.seek(0, 2) - callback.set_size(size) - f1.seek(0) - - self.mkdirs(self._parent(os.fspath(rpath)), exist_ok=True) - with self.open(rpath, "wb", **kwargs) as f2: - while f1.tell() < size: - data = f1.read(self.blocksize) - segment_len = f2.write(data) - if segment_len is None: - segment_len = len(data) - callback.relative_update(segment_len) - - def put( - self, - lpath, - rpath, - recursive=False, - callback=DEFAULT_CALLBACK, - maxdepth=None, - **kwargs, - ): - """Copy file(s) from local. - - Copies a specific file or tree of files (if recursive=True). If rpath - ends with a "/", it will be assumed to be a directory, and target files - will go within. - - Calls put_file for each source. - """ - if isinstance(lpath, list) and isinstance(rpath, list): - # No need to expand paths when both source and destination - # are provided as lists - rpaths = rpath - lpaths = lpath - else: - from .implementations.local import ( - LocalFileSystem, - make_path_posix, - trailing_sep, - ) - - source_is_str = isinstance(lpath, str) - if source_is_str: - lpath = make_path_posix(lpath) - fs = LocalFileSystem() - lpaths = fs.expand_path( - lpath, recursive=recursive, maxdepth=maxdepth, **kwargs - ) - if source_is_str and (not recursive or maxdepth is not None): - # Non-recursive glob does not copy directories - lpaths = [p for p in lpaths if not (trailing_sep(p) or fs.isdir(p))] - if not lpaths: - return - - source_is_file = len(lpaths) == 1 - dest_is_dir = isinstance(rpath, str) and ( - trailing_sep(rpath) or self.isdir(rpath) - ) - - rpath = ( - self._strip_protocol(rpath) - if isinstance(rpath, str) - else [self._strip_protocol(p) for p in rpath] - ) - exists = source_is_str and ( - (has_magic(lpath) and source_is_file) - or (not has_magic(lpath) and dest_is_dir and not trailing_sep(lpath)) - ) - rpaths = other_paths( - lpaths, - rpath, - exists=exists, - flatten=not source_is_str, - ) - - callback.set_size(len(rpaths)) - for lpath, rpath in callback.wrap(zip(lpaths, rpaths)): - with callback.branched(lpath, rpath) as child: - self.put_file(lpath, rpath, callback=child, **kwargs) - - def head(self, path, size=1024): - """Get the first ``size`` bytes from file""" - with self.open(path, "rb") as f: - return f.read(size) - - def tail(self, path, size=1024): - """Get the last ``size`` bytes from file""" - with self.open(path, "rb") as f: - f.seek(max(-size, -f.size), 2) - return f.read() - - def cp_file(self, path1, path2, **kwargs): - raise NotImplementedError - - def copy( - self, path1, path2, recursive=False, maxdepth=None, on_error=None, **kwargs - ): - """Copy within two locations in the filesystem - - on_error : "raise", "ignore" - If raise, any not-found exceptions will be raised; if ignore any - not-found exceptions will cause the path to be skipped; defaults to - raise unless recursive is true, where the default is ignore - """ - if on_error is None and recursive: - on_error = "ignore" - elif on_error is None: - on_error = "raise" - - if isinstance(path1, list) and isinstance(path2, list): - # No need to expand paths when both source and destination - # are provided as lists - paths1 = path1 - paths2 = path2 - else: - from .implementations.local import trailing_sep - - source_is_str = isinstance(path1, str) - paths1 = self.expand_path( - path1, recursive=recursive, maxdepth=maxdepth, **kwargs - ) - if source_is_str and (not recursive or maxdepth is not None): - # Non-recursive glob does not copy directories - paths1 = [p for p in paths1 if not (trailing_sep(p) or self.isdir(p))] - if not paths1: - return - - source_is_file = len(paths1) == 1 - dest_is_dir = isinstance(path2, str) and ( - trailing_sep(path2) or self.isdir(path2) - ) - - exists = source_is_str and ( - (has_magic(path1) and source_is_file) - or (not has_magic(path1) and dest_is_dir and not trailing_sep(path1)) - ) - paths2 = other_paths( - paths1, - path2, - exists=exists, - flatten=not source_is_str, - ) - - for p1, p2 in zip(paths1, paths2): - try: - self.cp_file(p1, p2, **kwargs) - except FileNotFoundError: - if on_error == "raise": - raise - - def expand_path(self, path, recursive=False, maxdepth=None, **kwargs): - """Turn one or more globs or directories into a list of all matching paths - to files or directories. - - kwargs are passed to ``glob`` or ``find``, which may in turn call ``ls`` - """ - - if maxdepth is not None and maxdepth < 1: - raise ValueError("maxdepth must be at least 1") - - if isinstance(path, (str, os.PathLike)): - out = self.expand_path([path], recursive, maxdepth, **kwargs) - else: - out = set() - path = [self._strip_protocol(p) for p in path] - for p in path: - if has_magic(p): - bit = set(self.glob(p, maxdepth=maxdepth, **kwargs)) - out |= bit - if recursive: - # glob call above expanded one depth so if maxdepth is defined - # then decrement it in expand_path call below. If it is zero - # after decrementing then avoid expand_path call. - if maxdepth is not None and maxdepth <= 1: - continue - out |= set( - self.expand_path( - list(bit), - recursive=recursive, - maxdepth=maxdepth - 1 if maxdepth is not None else None, - **kwargs, - ) - ) - continue - elif recursive: - rec = set( - self.find( - p, maxdepth=maxdepth, withdirs=True, detail=False, **kwargs - ) - ) - out |= rec - if p not in out and (recursive is False or self.exists(p)): - # should only check once, for the root - out.add(p) - if not out: - raise FileNotFoundError(path) - return sorted(out) - - def mv(self, path1, path2, recursive=False, maxdepth=None, **kwargs): - """Move file(s) from one location to another""" - if path1 == path2: - logger.debug("%s mv: The paths are the same, so no files were moved.", self) - else: - # explicitly raise exception to prevent data corruption - self.copy( - path1, path2, recursive=recursive, maxdepth=maxdepth, onerror="raise" - ) - self.rm(path1, recursive=recursive) - - def rm_file(self, path): - """Delete a file""" - self._rm(path) - - def _rm(self, path): - """Delete one file""" - # this is the old name for the method, prefer rm_file - raise NotImplementedError - - def rm(self, path, recursive=False, maxdepth=None): - """Delete files. - - Parameters - ---------- - path: str or list of str - File(s) to delete. - recursive: bool - If file(s) are directories, recursively delete contents and then - also remove the directory - maxdepth: int or None - Depth to pass to walk for finding files to delete, if recursive. - If None, there will be no limit and infinite recursion may be - possible. - """ - path = self.expand_path(path, recursive=recursive, maxdepth=maxdepth) - for p in reversed(path): - self.rm_file(p) - - @classmethod - def _parent(cls, path): - path = cls._strip_protocol(path) - if "/" in path: - parent = path.rsplit("/", 1)[0].lstrip(cls.root_marker) - return cls.root_marker + parent - else: - return cls.root_marker - - def _open( - self, - path, - mode="rb", - block_size=None, - autocommit=True, - cache_options=None, - **kwargs, - ): - """Return raw bytes-mode file-like from the file-system""" - return AbstractBufferedFile( - self, - path, - mode, - block_size, - autocommit, - cache_options=cache_options, - **kwargs, - ) - - def open( - self, - path, - mode="rb", - block_size=None, - cache_options=None, - compression=None, - **kwargs, - ): - """ - Return a file-like object from the filesystem - - The resultant instance must function correctly in a context ``with`` - block. - - Parameters - ---------- - path: str - Target file - mode: str like 'rb', 'w' - See builtin ``open()`` - Mode "x" (exclusive write) may be implemented by the backend. Even if - it is, whether it is checked up front or on commit, and whether it is - atomic is implementation-dependent. - block_size: int - Some indication of buffering - this is a value in bytes - cache_options : dict, optional - Extra arguments to pass through to the cache. - compression: string or None - If given, open file using compression codec. Can either be a compression - name (a key in ``fsspec.compression.compr``) or "infer" to guess the - compression from the filename suffix. - encoding, errors, newline: passed on to TextIOWrapper for text mode - """ - import io - - path = self._strip_protocol(path) - if "b" not in mode: - mode = mode.replace("t", "") + "b" - - text_kwargs = { - k: kwargs.pop(k) - for k in ["encoding", "errors", "newline"] - if k in kwargs - } - return io.TextIOWrapper( - self.open( - path, - mode, - block_size=block_size, - cache_options=cache_options, - compression=compression, - **kwargs, - ), - **text_kwargs, - ) - else: - ac = kwargs.pop("autocommit", not self._intrans) - f = self._open( - path, - mode=mode, - block_size=block_size, - autocommit=ac, - cache_options=cache_options, - **kwargs, - ) - if compression is not None: - from fsspec.compression import compr - from fsspec.core import get_compression - - compression = get_compression(path, compression) - compress = compr[compression] - f = compress(f, mode=mode[0]) - - if not ac and "r" not in mode: - self.transaction.files.append(f) - return f - - def touch(self, path, truncate=True, **kwargs): - """Create empty file, or update timestamp - - Parameters - ---------- - path: str - file location - truncate: bool - If True, always set file size to 0; if False, update timestamp and - leave file unchanged, if backend allows this - """ - if truncate or not self.exists(path): - with self.open(path, "wb", **kwargs): - pass - else: - raise NotImplementedError # update timestamp, if possible - - def ukey(self, path): - """Hash of file properties, to tell if it has changed""" - return sha256(str(self.info(path)).encode()).hexdigest() - - def read_block(self, fn, offset, length, delimiter=None): - """Read a block of bytes from - - Starting at ``offset`` of the file, read ``length`` bytes. If - ``delimiter`` is set then we ensure that the read starts and stops at - delimiter boundaries that follow the locations ``offset`` and ``offset - + length``. If ``offset`` is zero then we start at zero. The - bytestring returned WILL include the end delimiter string. - - If offset+length is beyond the eof, reads to eof. - - Parameters - ---------- - fn: string - Path to filename - offset: int - Byte offset to start read - length: int - Number of bytes to read. If None, read to end. - delimiter: bytes (optional) - Ensure reading starts and stops at delimiter bytestring - - Examples - -------- - >>> fs.read_block('data/file.csv', 0, 13) # doctest: +SKIP - b'Alice, 100\\nBo' - >>> fs.read_block('data/file.csv', 0, 13, delimiter=b'\\n') # doctest: +SKIP - b'Alice, 100\\nBob, 200\\n' - - Use ``length=None`` to read to the end of the file. - >>> fs.read_block('data/file.csv', 0, None, delimiter=b'\\n') # doctest: +SKIP - b'Alice, 100\\nBob, 200\\nCharlie, 300' - - See Also - -------- - :func:`fsspec.utils.read_block` - """ - with self.open(fn, "rb") as f: - size = f.size - if length is None: - length = size - if size is not None and offset + length > size: - length = size - offset - return read_block(f, offset, length, delimiter) - - def to_json(self, *, include_password: bool = True) -> str: - """ - JSON representation of this filesystem instance. - - Parameters - ---------- - include_password: bool, default True - Whether to include the password (if any) in the output. - - Returns - ------- - JSON string with keys ``cls`` (the python location of this class), - protocol (text name of this class's protocol, first one in case of - multiple), ``args`` (positional args, usually empty), and all other - keyword arguments as their own keys. - - Warnings - -------- - Serialized filesystems may contain sensitive information which have been - passed to the constructor, such as passwords and tokens. Make sure you - store and send them in a secure environment! - """ - from .json import FilesystemJSONEncoder - - return json.dumps( - self, - cls=type( - "_FilesystemJSONEncoder", - (FilesystemJSONEncoder,), - {"include_password": include_password}, - ), - ) - - @staticmethod - def from_json(blob: str) -> AbstractFileSystem: - """ - Recreate a filesystem instance from JSON representation. - - See ``.to_json()`` for the expected structure of the input. - - Parameters - ---------- - blob: str - - Returns - ------- - file system instance, not necessarily of this particular class. - - Warnings - -------- - This can import arbitrary modules (as determined by the ``cls`` key). - Make sure you haven't installed any modules that may execute malicious code - at import time. - """ - from .json import FilesystemJSONDecoder - - return json.loads(blob, cls=FilesystemJSONDecoder) - - def to_dict(self, *, include_password: bool = True) -> dict[str, Any]: - """ - JSON-serializable dictionary representation of this filesystem instance. - - Parameters - ---------- - include_password: bool, default True - Whether to include the password (if any) in the output. - - Returns - ------- - Dictionary with keys ``cls`` (the python location of this class), - protocol (text name of this class's protocol, first one in case of - multiple), ``args`` (positional args, usually empty), and all other - keyword arguments as their own keys. - - Warnings - -------- - Serialized filesystems may contain sensitive information which have been - passed to the constructor, such as passwords and tokens. Make sure you - store and send them in a secure environment! - """ - from .json import FilesystemJSONEncoder - - json_encoder = FilesystemJSONEncoder() - - cls = type(self) - proto = self.protocol - - storage_options = dict(self.storage_options) - if not include_password: - storage_options.pop("password", None) - - return dict( - cls=f"{cls.__module__}:{cls.__name__}", - protocol=proto[0] if isinstance(proto, (tuple, list)) else proto, - args=json_encoder.make_serializable(self.storage_args), - **json_encoder.make_serializable(storage_options), - ) - - @staticmethod - def from_dict(dct: dict[str, Any]) -> AbstractFileSystem: - """ - Recreate a filesystem instance from dictionary representation. - - See ``.to_dict()`` for the expected structure of the input. - - Parameters - ---------- - dct: Dict[str, Any] - - Returns - ------- - file system instance, not necessarily of this particular class. - - Warnings - -------- - This can import arbitrary modules (as determined by the ``cls`` key). - Make sure you haven't installed any modules that may execute malicious code - at import time. - """ - from .json import FilesystemJSONDecoder - - json_decoder = FilesystemJSONDecoder() - - dct = dict(dct) # Defensive copy - - cls = FilesystemJSONDecoder.try_resolve_fs_cls(dct) - if cls is None: - raise ValueError("Not a serialized AbstractFileSystem") - - dct.pop("cls", None) - dct.pop("protocol", None) - - return cls( - *json_decoder.unmake_serializable(dct.pop("args", ())), - **json_decoder.unmake_serializable(dct), - ) - - def _get_pyarrow_filesystem(self): - """ - Make a version of the FS instance which will be acceptable to pyarrow - """ - # all instances already also derive from pyarrow - return self - - def get_mapper(self, root="", check=False, create=False, missing_exceptions=None): - """Create key/value store based on this file-system - - Makes a MutableMapping interface to the FS at the given root path. - See ``fsspec.mapping.FSMap`` for further details. - """ - from .mapping import FSMap - - return FSMap( - root, - self, - check=check, - create=create, - missing_exceptions=missing_exceptions, - ) - - @classmethod - def clear_instance_cache(cls): - """ - Clear the cache of filesystem instances. - - Notes - ----- - Unless overridden by setting the ``cachable`` class attribute to False, - the filesystem class stores a reference to newly created instances. This - prevents Python's normal rules around garbage collection from working, - since the instances refcount will not drop to zero until - ``clear_instance_cache`` is called. - """ - cls._cache.clear() - - def created(self, path): - """Return the created timestamp of a file as a datetime.datetime""" - raise NotImplementedError - - def modified(self, path): - """Return the modified timestamp of a file as a datetime.datetime""" - raise NotImplementedError - - def tree( - self, - path: str = "/", - recursion_limit: int = 2, - max_display: int = 25, - display_size: bool = False, - prefix: str = "", - is_last: bool = True, - first: bool = True, - indent_size: int = 4, - ) -> str: - """ - Return a tree-like structure of the filesystem starting from the given path as a string. - - Parameters - ---------- - path: Root path to start traversal from - recursion_limit: Maximum depth of directory traversal - max_display: Maximum number of items to display per directory - display_size: Whether to display file sizes - prefix: Current line prefix for visual tree structure - is_last: Whether current item is last in its level - first: Whether this is the first call (displays root path) - indent_size: Number of spaces by indent - - Returns - ------- - str: A string representing the tree structure. - - Example - ------- - >>> from fsspec import filesystem - - >>> fs = filesystem('ftp', host='test.rebex.net', user='demo', password='password') - >>> tree = fs.tree(display_size=True, recursion_limit=3, indent_size=8, max_display=10) - >>> print(tree) - """ - - def format_bytes(n: int) -> str: - """Format bytes as text.""" - for prefix, k in ( - ("P", 2**50), - ("T", 2**40), - ("G", 2**30), - ("M", 2**20), - ("k", 2**10), - ): - if n >= 0.9 * k: - return f"{n / k:.2f} {prefix}b" - return f"{n}B" - - result = [] - - if first: - result.append(path) - - if recursion_limit: - indent = " " * indent_size - contents = self.ls(path, detail=True) - contents.sort( - key=lambda x: (x.get("type") != "directory", x.get("name", "")) - ) - - if max_display is not None and len(contents) > max_display: - displayed_contents = contents[:max_display] - remaining_count = len(contents) - max_display - else: - displayed_contents = contents - remaining_count = 0 - - for i, item in enumerate(displayed_contents): - is_last_item = (i == len(displayed_contents) - 1) and ( - remaining_count == 0 - ) - - branch = ( - "└" + ("─" * (indent_size - 2)) - if is_last_item - else "├" + ("─" * (indent_size - 2)) - ) - branch += " " - new_prefix = prefix + ( - indent if is_last_item else "│" + " " * (indent_size - 1) - ) - - name = os.path.basename(item.get("name", "")) - - if display_size and item.get("type") == "directory": - sub_contents = self.ls(item.get("name", ""), detail=True) - num_files = sum( - 1 for sub_item in sub_contents if sub_item.get("type") == "file" - ) - num_folders = sum( - 1 - for sub_item in sub_contents - if sub_item.get("type") == "directory" - ) - - if num_files == 0 and num_folders == 0: - size = " (empty folder)" - elif num_files == 0: - size = f" ({num_folders} subfolder{'s' if num_folders > 1 else ''})" - elif num_folders == 0: - size = f" ({num_files} file{'s' if num_files > 1 else ''})" - else: - size = f" ({num_files} file{'s' if num_files > 1 else ''}, {num_folders} subfolder{'s' if num_folders > 1 else ''})" - elif display_size and item.get("type") == "file": - size = f" ({format_bytes(item.get('size', 0))})" - else: - size = "" - - result.append(f"{prefix}{branch}{name}{size}") - - if item.get("type") == "directory" and recursion_limit > 0: - result.append( - self.tree( - path=item.get("name", ""), - recursion_limit=recursion_limit - 1, - max_display=max_display, - display_size=display_size, - prefix=new_prefix, - is_last=is_last_item, - first=False, - indent_size=indent_size, - ) - ) - - if remaining_count > 0: - more_message = f"{remaining_count} more item(s) not displayed." - result.append( - f"{prefix}{'└' + ('─' * (indent_size - 2))} {more_message}" - ) - - return "\n".join(_ for _ in result if _) - - # ------------------------------------------------------------------------ - # Aliases - - def read_bytes(self, path, start=None, end=None, **kwargs): - """Alias of `AbstractFileSystem.cat_file`.""" - return self.cat_file(path, start=start, end=end, **kwargs) - - def write_bytes(self, path, value, **kwargs): - """Alias of `AbstractFileSystem.pipe_file`.""" - self.pipe_file(path, value, **kwargs) - - def makedir(self, path, create_parents=True, **kwargs): - """Alias of `AbstractFileSystem.mkdir`.""" - return self.mkdir(path, create_parents=create_parents, **kwargs) - - def mkdirs(self, path, exist_ok=False): - """Alias of `AbstractFileSystem.makedirs`.""" - return self.makedirs(path, exist_ok=exist_ok) - - def listdir(self, path, detail=True, **kwargs): - """Alias of `AbstractFileSystem.ls`.""" - return self.ls(path, detail=detail, **kwargs) - - def cp(self, path1, path2, **kwargs): - """Alias of `AbstractFileSystem.copy`.""" - return self.copy(path1, path2, **kwargs) - - def move(self, path1, path2, **kwargs): - """Alias of `AbstractFileSystem.mv`.""" - return self.mv(path1, path2, **kwargs) - - def stat(self, path, **kwargs): - """Alias of `AbstractFileSystem.info`.""" - return self.info(path, **kwargs) - - def disk_usage(self, path, total=True, maxdepth=None, **kwargs): - """Alias of `AbstractFileSystem.du`.""" - return self.du(path, total=total, maxdepth=maxdepth, **kwargs) - - def rename(self, path1, path2, **kwargs): - """Alias of `AbstractFileSystem.mv`.""" - return self.mv(path1, path2, **kwargs) - - def delete(self, path, recursive=False, maxdepth=None): - """Alias of `AbstractFileSystem.rm`.""" - return self.rm(path, recursive=recursive, maxdepth=maxdepth) - - def upload(self, lpath, rpath, recursive=False, **kwargs): - """Alias of `AbstractFileSystem.put`.""" - return self.put(lpath, rpath, recursive=recursive, **kwargs) - - def download(self, rpath, lpath, recursive=False, **kwargs): - """Alias of `AbstractFileSystem.get`.""" - return self.get(rpath, lpath, recursive=recursive, **kwargs) - - def sign(self, path, expiration=100, **kwargs): - """Create a signed URL representing the given path - - Some implementations allow temporary URLs to be generated, as a - way of delegating credentials. - - Parameters - ---------- - path : str - The path on the filesystem - expiration : int - Number of seconds to enable the URL for (if supported) - - Returns - ------- - URL : str - The signed URL - - Raises - ------ - NotImplementedError : if method is not implemented for a filesystem - """ - raise NotImplementedError("Sign is not implemented for this filesystem") - - def _isfilestore(self): - # Originally inherited from pyarrow DaskFileSystem. Keeping this - # here for backwards compatibility as long as pyarrow uses its - # legacy fsspec-compatible filesystems and thus accepts fsspec - # filesystems as well - return False - - -class AbstractBufferedFile(io.IOBase): - """Convenient class to derive from to provide buffering - - In the case that the backend does not provide a pythonic file-like object - already, this class contains much of the logic to build one. The only - methods that need to be overridden are ``_upload_chunk``, - ``_initiate_upload`` and ``_fetch_range``. - """ - - DEFAULT_BLOCK_SIZE = 5 * 2**20 - _details = None - - def __init__( - self, - fs, - path, - mode="rb", - block_size="default", - autocommit=True, - cache_type="readahead", - cache_options=None, - size=None, - **kwargs, - ): - """ - Template for files with buffered reading and writing - - Parameters - ---------- - fs: instance of FileSystem - path: str - location in file-system - mode: str - Normal file modes. Currently only 'wb', 'ab' or 'rb'. Some file - systems may be read-only, and some may not support append. - block_size: int - Buffer size for reading or writing, 'default' for class default - autocommit: bool - Whether to write to final destination; may only impact what - happens when file is being closed. - cache_type: {"readahead", "none", "mmap", "bytes"}, default "readahead" - Caching policy in read mode. See the definitions in ``core``. - cache_options : dict - Additional options passed to the constructor for the cache specified - by `cache_type`. - size: int - If given and in read mode, suppressed having to look up the file size - kwargs: - Gets stored as self.kwargs - """ - from .core import caches - - self.path = path - self.fs = fs - self.mode = mode - self.blocksize = ( - self.DEFAULT_BLOCK_SIZE if block_size in ["default", None] else block_size - ) - self.loc = 0 - self.autocommit = autocommit - self.end = None - self.start = None - self.closed = False - - if cache_options is None: - cache_options = {} - - if "trim" in kwargs: - warnings.warn( - "Passing 'trim' to control the cache behavior has been deprecated. " - "Specify it within the 'cache_options' argument instead.", - FutureWarning, - ) - cache_options["trim"] = kwargs.pop("trim") - - self.kwargs = kwargs - - if mode not in {"ab", "rb", "wb", "xb"}: - raise NotImplementedError("File mode not supported") - if mode == "rb": - if size is not None: - self.size = size - else: - self.size = self.details["size"] - self.cache = caches[cache_type]( - self.blocksize, self._fetch_range, self.size, **cache_options - ) - else: - self.buffer = io.BytesIO() - self.offset = None - self.forced = False - self.location = None - - @property - def details(self): - if self._details is None: - self._details = self.fs.info(self.path) - return self._details - - @details.setter - def details(self, value): - self._details = value - self.size = value["size"] - - @property - def full_name(self): - return _unstrip_protocol(self.path, self.fs) - - @property - def closed(self): - # get around this attr being read-only in IOBase - # use getattr here, since this can be called during del - return getattr(self, "_closed", True) - - @closed.setter - def closed(self, c): - self._closed = c - - def __hash__(self): - if "w" in self.mode: - return id(self) - else: - return int(tokenize(self.details), 16) - - def __eq__(self, other): - """Files are equal if they have the same checksum, only in read mode""" - if self is other: - return True - return ( - isinstance(other, type(self)) - and self.mode == "rb" - and other.mode == "rb" - and hash(self) == hash(other) - ) - - def commit(self): - """Move from temp to final destination""" - - def discard(self): - """Throw away temporary file""" - - def info(self): - """File information about this path""" - if self.readable(): - return self.details - else: - raise ValueError("Info not available while writing") - - def tell(self): - """Current file location""" - return self.loc - - def seek(self, loc, whence=0): - """Set current file location - - Parameters - ---------- - loc: int - byte location - whence: {0, 1, 2} - from start of file, current location or end of file, resp. - """ - loc = int(loc) - if not self.mode == "rb": - raise OSError(ESPIPE, "Seek only available in read mode") - if whence == 0: - nloc = loc - elif whence == 1: - nloc = self.loc + loc - elif whence == 2: - nloc = self.size + loc - else: - raise ValueError(f"invalid whence ({whence}, should be 0, 1 or 2)") - if nloc < 0: - raise ValueError("Seek before start of file") - self.loc = nloc - return self.loc - - def write(self, data): - """ - Write data to buffer. - - Buffer only sent on flush() or if buffer is greater than - or equal to blocksize. - - Parameters - ---------- - data: bytes - Set of bytes to be written. - """ - if not self.writable(): - raise ValueError("File not in write mode") - if self.closed: - raise ValueError("I/O operation on closed file.") - if self.forced: - raise ValueError("This file has been force-flushed, can only close") - out = self.buffer.write(data) - self.loc += out - if self.buffer.tell() >= self.blocksize: - self.flush() - return out - - def flush(self, force=False): - """ - Write buffered data to backend store. - - Writes the current buffer, if it is larger than the block-size, or if - the file is being closed. - - Parameters - ---------- - force: bool - When closing, write the last block even if it is smaller than - blocks are allowed to be. Disallows further writing to this file. - """ - - if self.closed: - raise ValueError("Flush on closed file") - if force and self.forced: - raise ValueError("Force flush cannot be called more than once") - if force: - self.forced = True - - if self.readable(): - # no-op to flush on read-mode - return - - if not force and self.buffer.tell() < self.blocksize: - # Defer write on small block - return - - if self.offset is None: - # Initialize a multipart upload - self.offset = 0 - try: - self._initiate_upload() - except: - self.closed = True - raise - - if self._upload_chunk(final=force) is not False: - self.offset += self.buffer.seek(0, 2) - self.buffer = io.BytesIO() - - def _upload_chunk(self, final=False): - """Write one part of a multi-block file upload - - Parameters - ========== - final: bool - This is the last block, so should complete file, if - self.autocommit is True. - """ - # may not yet have been initialized, may need to call _initialize_upload - - def _initiate_upload(self): - """Create remote file/upload""" - pass - - def _fetch_range(self, start, end): - """Get the specified set of bytes from remote""" - return self.fs.cat_file(self.path, start=start, end=end) - - def read(self, length=-1): - """ - Return data from cache, or fetch pieces as necessary - - Parameters - ---------- - length: int (-1) - Number of bytes to read; if <0, all remaining bytes. - """ - length = -1 if length is None else int(length) - if self.mode != "rb": - raise ValueError("File not in read mode") - if length < 0: - length = self.size - self.loc - if self.closed: - raise ValueError("I/O operation on closed file.") - if length == 0: - # don't even bother calling fetch - return b"" - out = self.cache._fetch(self.loc, self.loc + length) - - logger.debug( - "%s read: %i - %i %s", - self, - self.loc, - self.loc + length, - self.cache._log_stats(), - ) - self.loc += len(out) - return out - - def readinto(self, b): - """mirrors builtin file's readinto method - - https://docs.python.org/3/library/io.html#io.RawIOBase.readinto - """ - out = memoryview(b).cast("B") - data = self.read(out.nbytes) - out[: len(data)] = data - return len(data) - - def readuntil(self, char=b"\n", blocks=None): - """Return data between current position and first occurrence of char - - char is included in the output, except if the end of the tile is - encountered first. - - Parameters - ---------- - char: bytes - Thing to find - blocks: None or int - How much to read in each go. Defaults to file blocksize - which may - mean a new read on every call. - """ - out = [] - while True: - start = self.tell() - part = self.read(blocks or self.blocksize) - if len(part) == 0: - break - found = part.find(char) - if found > -1: - out.append(part[: found + len(char)]) - self.seek(start + found + len(char)) - break - out.append(part) - return b"".join(out) - - def readline(self): - """Read until and including the first occurrence of newline character - - Note that, because of character encoding, this is not necessarily a - true line ending. - """ - return self.readuntil(b"\n") - - def __next__(self): - out = self.readline() - if out: - return out - raise StopIteration - - def __iter__(self): - return self - - def readlines(self): - """Return all data, split by the newline character, including the newline character""" - data = self.read() - lines = data.split(b"\n") - out = [l + b"\n" for l in lines[:-1]] - if data.endswith(b"\n"): - return out - else: - return out + [lines[-1]] - # return list(self) ??? - - def readinto1(self, b): - return self.readinto(b) - - def close(self): - """Close file - - Finalizes writes, discards cache - """ - if getattr(self, "_unclosable", False): - return - if self.closed: - return - try: - if self.mode == "rb": - self.cache = None - else: - if not self.forced: - self.flush(force=True) - - if self.fs is not None: - self.fs.invalidate_cache(self.path) - self.fs.invalidate_cache(self.fs._parent(self.path)) - finally: - self.closed = True - - def readable(self): - """Whether opened for reading""" - return "r" in self.mode and not self.closed - - def seekable(self): - """Whether is seekable (only in read mode)""" - return self.readable() - - def writable(self): - """Whether opened for writing""" - return self.mode in {"wb", "ab", "xb"} and not self.closed - - def __reduce__(self): - if self.mode != "rb": - raise RuntimeError("Pickling a writeable file is not supported") - - return reopen, ( - self.fs, - self.path, - self.mode, - self.blocksize, - self.loc, - self.size, - self.autocommit, - self.cache.name if self.cache else "none", - self.kwargs, - ) - - def __del__(self): - if not self.closed: - self.close() - - def __str__(self): - return f"" - - __repr__ = __str__ - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - -def reopen(fs, path, mode, blocksize, loc, size, autocommit, cache_type, kwargs): - file = fs.open( - path, - mode=mode, - block_size=blocksize, - autocommit=autocommit, - cache_type=cache_type, - size=size, - **kwargs, - ) - if loc > 0: - file.seek(loc) - return file diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__init__.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__init__.py deleted file mode 100644 index 8ed2ad802ecaf021106c25c03112f29e75c7b2f8..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__init__.py +++ /dev/null @@ -1,289 +0,0 @@ -import os -from hashlib import md5 - -import pytest - -from fsspec.implementations.local import LocalFileSystem -from fsspec.tests.abstract.copy import AbstractCopyTests # noqa: F401 -from fsspec.tests.abstract.get import AbstractGetTests # noqa: F401 -from fsspec.tests.abstract.open import AbstractOpenTests # noqa: F401 -from fsspec.tests.abstract.pipe import AbstractPipeTests # noqa: F401 -from fsspec.tests.abstract.put import AbstractPutTests # noqa: F401 - - -class BaseAbstractFixtures: - """ - Abstract base class containing fixtures that are used by but never need to - be overridden in derived filesystem-specific classes to run the abstract - tests on such filesystems. - """ - - @pytest.fixture - def fs_bulk_operations_scenario_0(self, fs, fs_join, fs_path): - """ - Scenario on remote filesystem that is used for many cp/get/put tests. - - Cleans up at the end of each test it which it is used. - """ - source = self._bulk_operations_scenario_0(fs, fs_join, fs_path) - yield source - fs.rm(source, recursive=True) - - @pytest.fixture - def fs_glob_edge_cases_files(self, fs, fs_join, fs_path): - """ - Scenario on remote filesystem that is used for glob edge cases cp/get/put tests. - - Cleans up at the end of each test it which it is used. - """ - source = self._glob_edge_cases_files(fs, fs_join, fs_path) - yield source - fs.rm(source, recursive=True) - - @pytest.fixture - def fs_dir_and_file_with_same_name_prefix(self, fs, fs_join, fs_path): - """ - Scenario on remote filesystem that is used to check cp/get/put on directory - and file with the same name prefixes. - - Cleans up at the end of each test it which it is used. - """ - source = self._dir_and_file_with_same_name_prefix(fs, fs_join, fs_path) - yield source - fs.rm(source, recursive=True) - - @pytest.fixture - def fs_10_files_with_hashed_names(self, fs, fs_join, fs_path): - """ - Scenario on remote filesystem that is used to check cp/get/put files order - when source and destination are lists. - - Cleans up at the end of each test it which it is used. - """ - source = self._10_files_with_hashed_names(fs, fs_join, fs_path) - yield source - fs.rm(source, recursive=True) - - @pytest.fixture - def fs_target(self, fs, fs_join, fs_path): - """ - Return name of remote directory that does not yet exist to copy into. - - Cleans up at the end of each test it which it is used. - """ - target = fs_join(fs_path, "target") - yield target - if fs.exists(target): - fs.rm(target, recursive=True) - - @pytest.fixture - def local_bulk_operations_scenario_0(self, local_fs, local_join, local_path): - """ - Scenario on local filesystem that is used for many cp/get/put tests. - - Cleans up at the end of each test it which it is used. - """ - source = self._bulk_operations_scenario_0(local_fs, local_join, local_path) - yield source - local_fs.rm(source, recursive=True) - - @pytest.fixture - def local_glob_edge_cases_files(self, local_fs, local_join, local_path): - """ - Scenario on local filesystem that is used for glob edge cases cp/get/put tests. - - Cleans up at the end of each test it which it is used. - """ - source = self._glob_edge_cases_files(local_fs, local_join, local_path) - yield source - local_fs.rm(source, recursive=True) - - @pytest.fixture - def local_dir_and_file_with_same_name_prefix( - self, local_fs, local_join, local_path - ): - """ - Scenario on local filesystem that is used to check cp/get/put on directory - and file with the same name prefixes. - - Cleans up at the end of each test it which it is used. - """ - source = self._dir_and_file_with_same_name_prefix( - local_fs, local_join, local_path - ) - yield source - local_fs.rm(source, recursive=True) - - @pytest.fixture - def local_10_files_with_hashed_names(self, local_fs, local_join, local_path): - """ - Scenario on local filesystem that is used to check cp/get/put files order - when source and destination are lists. - - Cleans up at the end of each test it which it is used. - """ - source = self._10_files_with_hashed_names(local_fs, local_join, local_path) - yield source - local_fs.rm(source, recursive=True) - - @pytest.fixture - def local_target(self, local_fs, local_join, local_path): - """ - Return name of local directory that does not yet exist to copy into. - - Cleans up at the end of each test it which it is used. - """ - target = local_join(local_path, "target") - yield target - if local_fs.exists(target): - local_fs.rm(target, recursive=True) - - def _glob_edge_cases_files(self, some_fs, some_join, some_path): - """ - Scenario that is used for glob edge cases cp/get/put tests. - Creates the following directory and file structure: - - 📁 source - ├── 📄 file1 - ├── 📄 file2 - ├── 📁 subdir0 - │ ├── 📄 subfile1 - │ ├── 📄 subfile2 - │ └── 📁 nesteddir - │ └── 📄 nestedfile - └── 📁 subdir1 - ├── 📄 subfile1 - ├── 📄 subfile2 - └── 📁 nesteddir - └── 📄 nestedfile - """ - source = some_join(some_path, "source") - some_fs.touch(some_join(source, "file1")) - some_fs.touch(some_join(source, "file2")) - - for subdir_idx in range(2): - subdir = some_join(source, f"subdir{subdir_idx}") - nesteddir = some_join(subdir, "nesteddir") - some_fs.makedirs(nesteddir) - some_fs.touch(some_join(subdir, "subfile1")) - some_fs.touch(some_join(subdir, "subfile2")) - some_fs.touch(some_join(nesteddir, "nestedfile")) - - return source - - def _bulk_operations_scenario_0(self, some_fs, some_join, some_path): - """ - Scenario that is used for many cp/get/put tests. Creates the following - directory and file structure: - - 📁 source - ├── 📄 file1 - ├── 📄 file2 - └── 📁 subdir - ├── 📄 subfile1 - ├── 📄 subfile2 - └── 📁 nesteddir - └── 📄 nestedfile - """ - source = some_join(some_path, "source") - subdir = some_join(source, "subdir") - nesteddir = some_join(subdir, "nesteddir") - some_fs.makedirs(nesteddir) - some_fs.touch(some_join(source, "file1")) - some_fs.touch(some_join(source, "file2")) - some_fs.touch(some_join(subdir, "subfile1")) - some_fs.touch(some_join(subdir, "subfile2")) - some_fs.touch(some_join(nesteddir, "nestedfile")) - return source - - def _dir_and_file_with_same_name_prefix(self, some_fs, some_join, some_path): - """ - Scenario that is used to check cp/get/put on directory and file with - the same name prefixes. Creates the following directory and file structure: - - 📁 source - ├── 📄 subdir.txt - └── 📁 subdir - └── 📄 subfile.txt - """ - source = some_join(some_path, "source") - subdir = some_join(source, "subdir") - file = some_join(source, "subdir.txt") - subfile = some_join(subdir, "subfile.txt") - some_fs.makedirs(subdir) - some_fs.touch(file) - some_fs.touch(subfile) - return source - - def _10_files_with_hashed_names(self, some_fs, some_join, some_path): - """ - Scenario that is used to check cp/get/put files order when source and - destination are lists. Creates the following directory and file structure: - - 📁 source - └── 📄 {hashed([0-9])}.txt - """ - source = some_join(some_path, "source") - for i in range(10): - hashed_i = md5(str(i).encode("utf-8")).hexdigest() - path = some_join(source, f"{hashed_i}.txt") - some_fs.pipe(path=path, value=f"{i}".encode()) - return source - - -class AbstractFixtures(BaseAbstractFixtures): - """ - Abstract base class containing fixtures that may be overridden in derived - filesystem-specific classes to run the abstract tests on such filesystems. - - For any particular filesystem some of these fixtures must be overridden, - such as ``fs`` and ``fs_path``, and others may be overridden if the - default functions here are not appropriate, such as ``fs_join``. - """ - - @pytest.fixture - def fs(self): - raise NotImplementedError("This function must be overridden in derived classes") - - @pytest.fixture - def fs_join(self): - """ - Return a function that joins its arguments together into a path. - - Most fsspec implementations join paths in a platform-dependent way, - but some will override this to always use a forward slash. - """ - return os.path.join - - @pytest.fixture - def fs_path(self): - raise NotImplementedError("This function must be overridden in derived classes") - - @pytest.fixture(scope="class") - def local_fs(self): - # Maybe need an option for auto_mkdir=False? This is only relevant - # for certain implementations. - return LocalFileSystem(auto_mkdir=True) - - @pytest.fixture - def local_join(self): - """ - Return a function that joins its arguments together into a path, on - the local filesystem. - """ - return os.path.join - - @pytest.fixture - def local_path(self, tmpdir): - return tmpdir - - @pytest.fixture - def supports_empty_directories(self): - """ - Return whether this implementation supports empty directories. - """ - return True - - @pytest.fixture - def fs_sanitize_path(self): - return lambda x: x diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index d60f94b101cb89ac931cf869cc3be2b9e147e03a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/common.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/common.cpython-310.pyc deleted file mode 100644 index a9bc648f5796b2bc3905833037a207b1ec79539b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/common.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/copy.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/copy.cpython-310.pyc deleted file mode 100644 index 59cbb1cef8e0178f6b13414de143c85f5584792b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/copy.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/get.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/get.cpython-310.pyc deleted file mode 100644 index 904766803bb4e53c70ad714e396786318b275961..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/get.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/mv.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/mv.cpython-310.pyc deleted file mode 100644 index 16224b838ac1455e9a3a9b18607c428c7078f143..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/mv.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/open.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/open.cpython-310.pyc deleted file mode 100644 index dec6b55e7974a2207b7b78b9839e844ad96c1c13..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/open.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/pipe.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/pipe.cpython-310.pyc deleted file mode 100644 index 718c99bcf9e2ad8c1e510691826012346417fdb8..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/pipe.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/put.cpython-310.pyc b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/put.cpython-310.pyc deleted file mode 100644 index e8c13071a73e00d82651e22b634254b8dcc196a1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/__pycache__/put.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/common.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/common.py deleted file mode 100644 index 22e7c4140404ab2a8928689721419cf05c2760b9..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/common.py +++ /dev/null @@ -1,175 +0,0 @@ -GLOB_EDGE_CASES_TESTS = { - "argnames": ("path", "recursive", "maxdepth", "expected"), - "argvalues": [ - ("fil?1", False, None, ["file1"]), - ("fil?1", True, None, ["file1"]), - ("file[1-2]", False, None, ["file1", "file2"]), - ("file[1-2]", True, None, ["file1", "file2"]), - ("*", False, None, ["file1", "file2"]), - ( - "*", - True, - None, - [ - "file1", - "file2", - "subdir0/subfile1", - "subdir0/subfile2", - "subdir0/nesteddir/nestedfile", - "subdir1/subfile1", - "subdir1/subfile2", - "subdir1/nesteddir/nestedfile", - ], - ), - ("*", True, 1, ["file1", "file2"]), - ( - "*", - True, - 2, - [ - "file1", - "file2", - "subdir0/subfile1", - "subdir0/subfile2", - "subdir1/subfile1", - "subdir1/subfile2", - ], - ), - ("*1", False, None, ["file1"]), - ( - "*1", - True, - None, - [ - "file1", - "subdir1/subfile1", - "subdir1/subfile2", - "subdir1/nesteddir/nestedfile", - ], - ), - ("*1", True, 2, ["file1", "subdir1/subfile1", "subdir1/subfile2"]), - ( - "**", - False, - None, - [ - "file1", - "file2", - "subdir0/subfile1", - "subdir0/subfile2", - "subdir0/nesteddir/nestedfile", - "subdir1/subfile1", - "subdir1/subfile2", - "subdir1/nesteddir/nestedfile", - ], - ), - ( - "**", - True, - None, - [ - "file1", - "file2", - "subdir0/subfile1", - "subdir0/subfile2", - "subdir0/nesteddir/nestedfile", - "subdir1/subfile1", - "subdir1/subfile2", - "subdir1/nesteddir/nestedfile", - ], - ), - ("**", True, 1, ["file1", "file2"]), - ( - "**", - True, - 2, - [ - "file1", - "file2", - "subdir0/subfile1", - "subdir0/subfile2", - "subdir0/nesteddir/nestedfile", - "subdir1/subfile1", - "subdir1/subfile2", - "subdir1/nesteddir/nestedfile", - ], - ), - ( - "**", - False, - 2, - [ - "file1", - "file2", - "subdir0/subfile1", - "subdir0/subfile2", - "subdir1/subfile1", - "subdir1/subfile2", - ], - ), - ("**/*1", False, None, ["file1", "subdir0/subfile1", "subdir1/subfile1"]), - ( - "**/*1", - True, - None, - [ - "file1", - "subdir0/subfile1", - "subdir1/subfile1", - "subdir1/subfile2", - "subdir1/nesteddir/nestedfile", - ], - ), - ("**/*1", True, 1, ["file1"]), - ( - "**/*1", - True, - 2, - ["file1", "subdir0/subfile1", "subdir1/subfile1", "subdir1/subfile2"], - ), - ("**/*1", False, 2, ["file1", "subdir0/subfile1", "subdir1/subfile1"]), - ("**/subdir0", False, None, []), - ("**/subdir0", True, None, ["subfile1", "subfile2", "nesteddir/nestedfile"]), - ("**/subdir0/nested*", False, 2, []), - ("**/subdir0/nested*", True, 2, ["nestedfile"]), - ("subdir[1-2]", False, None, []), - ("subdir[1-2]", True, None, ["subfile1", "subfile2", "nesteddir/nestedfile"]), - ("subdir[1-2]", True, 2, ["subfile1", "subfile2"]), - ("subdir[0-1]", False, None, []), - ( - "subdir[0-1]", - True, - None, - [ - "subdir0/subfile1", - "subdir0/subfile2", - "subdir0/nesteddir/nestedfile", - "subdir1/subfile1", - "subdir1/subfile2", - "subdir1/nesteddir/nestedfile", - ], - ), - ( - "subdir[0-1]/*fil[e]*", - False, - None, - [ - "subdir0/subfile1", - "subdir0/subfile2", - "subdir1/subfile1", - "subdir1/subfile2", - ], - ), - ( - "subdir[0-1]/*fil[e]*", - True, - None, - [ - "subdir0/subfile1", - "subdir0/subfile2", - "subdir1/subfile1", - "subdir1/subfile2", - ], - ), - ], -} diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/copy.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/copy.py deleted file mode 100644 index e39e57e5f7d52bfda8ab5e2398b04cc2303630a0..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/copy.py +++ /dev/null @@ -1,557 +0,0 @@ -from hashlib import md5 -from itertools import product - -import pytest - -from fsspec.tests.abstract.common import GLOB_EDGE_CASES_TESTS - - -class AbstractCopyTests: - def test_copy_file_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - fs_target, - supports_empty_directories, - ): - # Copy scenario 1a - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - fs.touch(fs_join(target, "dummy")) - assert fs.isdir(target) - - target_file2 = fs_join(target, "file2") - target_subfile1 = fs_join(target, "subfile1") - - # Copy from source directory - fs.cp(fs_join(source, "file2"), target) - assert fs.isfile(target_file2) - - # Copy from sub directory - fs.cp(fs_join(source, "subdir", "subfile1"), target) - assert fs.isfile(target_subfile1) - - # Remove copied files - fs.rm([target_file2, target_subfile1]) - assert not fs.exists(target_file2) - assert not fs.exists(target_subfile1) - - # Repeat with trailing slash on target - fs.cp(fs_join(source, "file2"), target + "/") - assert fs.isdir(target) - assert fs.isfile(target_file2) - - fs.cp(fs_join(source, "subdir", "subfile1"), target + "/") - assert fs.isfile(target_subfile1) - - def test_copy_file_to_new_directory( - self, fs, fs_join, fs_bulk_operations_scenario_0, fs_target - ): - # Copy scenario 1b - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - fs.cp( - fs_join(source, "subdir", "subfile1"), fs_join(target, "newdir/") - ) # Note trailing slash - assert fs.isdir(target) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - - def test_copy_file_to_file_in_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - fs_target, - supports_empty_directories, - ): - # Copy scenario 1c - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - fs.touch(fs_join(target, "dummy")) - assert fs.isdir(target) - - fs.cp(fs_join(source, "subdir", "subfile1"), fs_join(target, "newfile")) - assert fs.isfile(fs_join(target, "newfile")) - - def test_copy_file_to_file_in_new_directory( - self, fs, fs_join, fs_bulk_operations_scenario_0, fs_target - ): - # Copy scenario 1d - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - fs.cp( - fs_join(source, "subdir", "subfile1"), fs_join(target, "newdir", "newfile") - ) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "newfile")) - - def test_copy_directory_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - fs_target, - supports_empty_directories, - ): - # Copy scenario 1e - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - dummy = fs_join(target, "dummy") - fs.touch(dummy) - assert fs.isdir(target) - - for source_slash, target_slash in zip([False, True], [False, True]): - s = fs_join(source, "subdir") - if source_slash: - s += "/" - t = target + "/" if target_slash else target - - # Without recursive does nothing - fs.cp(s, t) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # With recursive - fs.cp(s, t, recursive=True) - if source_slash: - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert fs.isdir(fs_join(target, "nesteddir")) - assert fs.isfile(fs_join(target, "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - fs_join(target, "nesteddir"), - ], - recursive=True, - ) - else: - assert fs.isdir(fs_join(target, "subdir")) - assert fs.isfile(fs_join(target, "subdir", "subfile1")) - assert fs.isfile(fs_join(target, "subdir", "subfile2")) - assert fs.isdir(fs_join(target, "subdir", "nesteddir")) - assert fs.isfile(fs_join(target, "subdir", "nesteddir", "nestedfile")) - - fs.rm(fs_join(target, "subdir"), recursive=True) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # Limit recursive by maxdepth - fs.cp(s, t, recursive=True, maxdepth=1) - if source_slash: - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert not fs.exists(fs_join(target, "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - ], - recursive=True, - ) - else: - assert fs.isdir(fs_join(target, "subdir")) - assert fs.isfile(fs_join(target, "subdir", "subfile1")) - assert fs.isfile(fs_join(target, "subdir", "subfile2")) - assert not fs.exists(fs_join(target, "subdir", "nesteddir")) - - fs.rm(fs_join(target, "subdir"), recursive=True) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - def test_copy_directory_to_new_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - fs_target, - supports_empty_directories, - ): - # Copy scenario 1f - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - for source_slash, target_slash in zip([False, True], [False, True]): - s = fs_join(source, "subdir") - if source_slash: - s += "/" - t = fs_join(target, "newdir") - if target_slash: - t += "/" - - # Without recursive does nothing - fs.cp(s, t) - if supports_empty_directories: - assert fs.ls(target) == [] - else: - with pytest.raises(FileNotFoundError): - fs.ls(target) - - # With recursive - fs.cp(s, t, recursive=True) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert fs.isdir(fs_join(target, "newdir", "nesteddir")) - assert fs.isfile(fs_join(target, "newdir", "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - # Limit recursive by maxdepth - fs.cp(s, t, recursive=True, maxdepth=1) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - def test_copy_glob_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - fs_target, - supports_empty_directories, - ): - # Copy scenario 1g - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - dummy = fs_join(target, "dummy") - fs.touch(dummy) - assert fs.isdir(target) - - for target_slash in [False, True]: - t = target + "/" if target_slash else target - - # Without recursive - fs.cp(fs_join(source, "subdir", "*"), t) - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert not fs.isdir(fs_join(target, "nesteddir")) - assert not fs.exists(fs_join(target, "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # With recursive - for glob, recursive in zip(["*", "**"], [True, False]): - fs.cp(fs_join(source, "subdir", glob), t, recursive=recursive) - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert fs.isdir(fs_join(target, "nesteddir")) - assert fs.isfile(fs_join(target, "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - fs_join(target, "nesteddir"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # Limit recursive by maxdepth - fs.cp( - fs_join(source, "subdir", glob), t, recursive=recursive, maxdepth=1 - ) - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert not fs.exists(fs_join(target, "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - def test_copy_glob_to_new_directory( - self, fs, fs_join, fs_bulk_operations_scenario_0, fs_target - ): - # Copy scenario 1h - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - for target_slash in [False, True]: - t = fs_join(target, "newdir") - if target_slash: - t += "/" - - # Without recursive - fs.cp(fs_join(source, "subdir", "*"), t) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - assert not fs.exists(fs_join(target, "newdir", "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - # With recursive - for glob, recursive in zip(["*", "**"], [True, False]): - fs.cp(fs_join(source, "subdir", glob), t, recursive=recursive) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert fs.isdir(fs_join(target, "newdir", "nesteddir")) - assert fs.isfile(fs_join(target, "newdir", "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - assert not fs.exists(fs_join(target, "newdir", "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - # Limit recursive by maxdepth - fs.cp( - fs_join(source, "subdir", glob), t, recursive=recursive, maxdepth=1 - ) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - assert not fs.exists(fs_join(target, "newdir", "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - @pytest.mark.parametrize( - GLOB_EDGE_CASES_TESTS["argnames"], - GLOB_EDGE_CASES_TESTS["argvalues"], - ) - def test_copy_glob_edge_cases( - self, - path, - recursive, - maxdepth, - expected, - fs, - fs_join, - fs_glob_edge_cases_files, - fs_target, - fs_sanitize_path, - ): - # Copy scenario 1g - source = fs_glob_edge_cases_files - - target = fs_target - - for new_dir, target_slash in product([True, False], [True, False]): - fs.mkdir(target) - - t = fs_join(target, "newdir") if new_dir else target - t = t + "/" if target_slash else t - - fs.copy(fs_join(source, path), t, recursive=recursive, maxdepth=maxdepth) - - output = fs.find(target) - if new_dir: - prefixed_expected = [ - fs_sanitize_path(fs_join(target, "newdir", p)) for p in expected - ] - else: - prefixed_expected = [ - fs_sanitize_path(fs_join(target, p)) for p in expected - ] - assert sorted(output) == sorted(prefixed_expected) - - try: - fs.rm(target, recursive=True) - except FileNotFoundError: - pass - - def test_copy_list_of_files_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - fs_target, - supports_empty_directories, - ): - # Copy scenario 2a - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - dummy = fs_join(target, "dummy") - fs.touch(dummy) - assert fs.isdir(target) - - source_files = [ - fs_join(source, "file1"), - fs_join(source, "file2"), - fs_join(source, "subdir", "subfile1"), - ] - - for target_slash in [False, True]: - t = target + "/" if target_slash else target - - fs.cp(source_files, t) - assert fs.isfile(fs_join(target, "file1")) - assert fs.isfile(fs_join(target, "file2")) - assert fs.isfile(fs_join(target, "subfile1")) - - fs.rm( - [ - fs_join(target, "file1"), - fs_join(target, "file2"), - fs_join(target, "subfile1"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - def test_copy_list_of_files_to_new_directory( - self, fs, fs_join, fs_bulk_operations_scenario_0, fs_target - ): - # Copy scenario 2b - source = fs_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - source_files = [ - fs_join(source, "file1"), - fs_join(source, "file2"), - fs_join(source, "subdir", "subfile1"), - ] - - fs.cp(source_files, fs_join(target, "newdir") + "/") # Note trailing slash - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "file1")) - assert fs.isfile(fs_join(target, "newdir", "file2")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - - def test_copy_two_files_new_directory( - self, fs, fs_join, fs_bulk_operations_scenario_0, fs_target - ): - # This is a duplicate of test_copy_list_of_files_to_new_directory and - # can eventually be removed. - source = fs_bulk_operations_scenario_0 - - target = fs_target - assert not fs.exists(target) - fs.cp([fs_join(source, "file1"), fs_join(source, "file2")], target) - - assert fs.isdir(target) - assert fs.isfile(fs_join(target, "file1")) - assert fs.isfile(fs_join(target, "file2")) - - def test_copy_directory_without_files_with_same_name_prefix( - self, - fs, - fs_join, - fs_target, - fs_dir_and_file_with_same_name_prefix, - supports_empty_directories, - ): - # Create the test dirs - source = fs_dir_and_file_with_same_name_prefix - target = fs_target - - # Test without glob - fs.cp(fs_join(source, "subdir"), target, recursive=True) - - assert fs.isfile(fs_join(target, "subfile.txt")) - assert not fs.isfile(fs_join(target, "subdir.txt")) - - fs.rm([fs_join(target, "subfile.txt")]) - if supports_empty_directories: - assert fs.ls(target) == [] - else: - assert not fs.exists(target) - - # Test with glob - fs.cp(fs_join(source, "subdir*"), target, recursive=True) - - assert fs.isdir(fs_join(target, "subdir")) - assert fs.isfile(fs_join(target, "subdir", "subfile.txt")) - assert fs.isfile(fs_join(target, "subdir.txt")) - - def test_copy_with_source_and_destination_as_list( - self, fs, fs_target, fs_join, fs_10_files_with_hashed_names - ): - # Create the test dir - source = fs_10_files_with_hashed_names - target = fs_target - - # Create list of files for source and destination - source_files = [] - destination_files = [] - for i in range(10): - hashed_i = md5(str(i).encode("utf-8")).hexdigest() - source_files.append(fs_join(source, f"{hashed_i}.txt")) - destination_files.append(fs_join(target, f"{hashed_i}.txt")) - - # Copy and assert order was kept - fs.copy(path1=source_files, path2=destination_files) - - for i in range(10): - file_content = fs.cat(destination_files[i]).decode("utf-8") - assert file_content == str(i) diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/get.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/get.py deleted file mode 100644 index 851ab81ee581e74cac41c64c83ef0af75826d6b0..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/get.py +++ /dev/null @@ -1,587 +0,0 @@ -from hashlib import md5 -from itertools import product - -import pytest - -from fsspec.implementations.local import make_path_posix -from fsspec.tests.abstract.common import GLOB_EDGE_CASES_TESTS - - -class AbstractGetTests: - def test_get_file_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1a - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - assert local_fs.isdir(target) - - target_file2 = local_join(target, "file2") - target_subfile1 = local_join(target, "subfile1") - - # Copy from source directory - fs.get(fs_join(source, "file2"), target) - assert local_fs.isfile(target_file2) - - # Copy from sub directory - fs.get(fs_join(source, "subdir", "subfile1"), target) - assert local_fs.isfile(target_subfile1) - - # Remove copied files - local_fs.rm([target_file2, target_subfile1]) - assert not local_fs.exists(target_file2) - assert not local_fs.exists(target_subfile1) - - # Repeat with trailing slash on target - fs.get(fs_join(source, "file2"), target + "/") - assert local_fs.isdir(target) - assert local_fs.isfile(target_file2) - - fs.get(fs_join(source, "subdir", "subfile1"), target + "/") - assert local_fs.isfile(target_subfile1) - - def test_get_file_to_new_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1b - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - fs.get( - fs_join(source, "subdir", "subfile1"), local_join(target, "newdir/") - ) # Note trailing slash - - assert local_fs.isdir(target) - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "subfile1")) - - def test_get_file_to_file_in_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1c - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - fs.get(fs_join(source, "subdir", "subfile1"), local_join(target, "newfile")) - assert local_fs.isfile(local_join(target, "newfile")) - - def test_get_file_to_file_in_new_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1d - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - fs.get( - fs_join(source, "subdir", "subfile1"), - local_join(target, "newdir", "newfile"), - ) - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "newfile")) - - def test_get_directory_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1e - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - assert local_fs.isdir(target) - - for source_slash, target_slash in zip([False, True], [False, True]): - s = fs_join(source, "subdir") - if source_slash: - s += "/" - t = target + "/" if target_slash else target - - # Without recursive does nothing - fs.get(s, t) - assert local_fs.ls(target) == [] - - # With recursive - fs.get(s, t, recursive=True) - if source_slash: - assert local_fs.isfile(local_join(target, "subfile1")) - assert local_fs.isfile(local_join(target, "subfile2")) - assert local_fs.isdir(local_join(target, "nesteddir")) - assert local_fs.isfile(local_join(target, "nesteddir", "nestedfile")) - assert not local_fs.exists(local_join(target, "subdir")) - - local_fs.rm( - [ - local_join(target, "subfile1"), - local_join(target, "subfile2"), - local_join(target, "nesteddir"), - ], - recursive=True, - ) - else: - assert local_fs.isdir(local_join(target, "subdir")) - assert local_fs.isfile(local_join(target, "subdir", "subfile1")) - assert local_fs.isfile(local_join(target, "subdir", "subfile2")) - assert local_fs.isdir(local_join(target, "subdir", "nesteddir")) - assert local_fs.isfile( - local_join(target, "subdir", "nesteddir", "nestedfile") - ) - - local_fs.rm(local_join(target, "subdir"), recursive=True) - assert local_fs.ls(target) == [] - - # Limit recursive by maxdepth - fs.get(s, t, recursive=True, maxdepth=1) - if source_slash: - assert local_fs.isfile(local_join(target, "subfile1")) - assert local_fs.isfile(local_join(target, "subfile2")) - assert not local_fs.exists(local_join(target, "nesteddir")) - assert not local_fs.exists(local_join(target, "subdir")) - - local_fs.rm( - [ - local_join(target, "subfile1"), - local_join(target, "subfile2"), - ], - recursive=True, - ) - else: - assert local_fs.isdir(local_join(target, "subdir")) - assert local_fs.isfile(local_join(target, "subdir", "subfile1")) - assert local_fs.isfile(local_join(target, "subdir", "subfile2")) - assert not local_fs.exists(local_join(target, "subdir", "nesteddir")) - - local_fs.rm(local_join(target, "subdir"), recursive=True) - assert local_fs.ls(target) == [] - - def test_get_directory_to_new_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1f - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - for source_slash, target_slash in zip([False, True], [False, True]): - s = fs_join(source, "subdir") - if source_slash: - s += "/" - t = local_join(target, "newdir") - if target_slash: - t += "/" - - # Without recursive does nothing - fs.get(s, t) - assert local_fs.ls(target) == [] - - # With recursive - fs.get(s, t, recursive=True) - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "subfile1")) - assert local_fs.isfile(local_join(target, "newdir", "subfile2")) - assert local_fs.isdir(local_join(target, "newdir", "nesteddir")) - assert local_fs.isfile( - local_join(target, "newdir", "nesteddir", "nestedfile") - ) - assert not local_fs.exists(local_join(target, "subdir")) - - local_fs.rm(local_join(target, "newdir"), recursive=True) - assert local_fs.ls(target) == [] - - # Limit recursive by maxdepth - fs.get(s, t, recursive=True, maxdepth=1) - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "subfile1")) - assert local_fs.isfile(local_join(target, "newdir", "subfile2")) - assert not local_fs.exists(local_join(target, "newdir", "nesteddir")) - assert not local_fs.exists(local_join(target, "subdir")) - - local_fs.rm(local_join(target, "newdir"), recursive=True) - assert not local_fs.exists(local_join(target, "newdir")) - - def test_get_glob_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1g - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - for target_slash in [False, True]: - t = target + "/" if target_slash else target - - # Without recursive - fs.get(fs_join(source, "subdir", "*"), t) - assert local_fs.isfile(local_join(target, "subfile1")) - assert local_fs.isfile(local_join(target, "subfile2")) - assert not local_fs.isdir(local_join(target, "nesteddir")) - assert not local_fs.exists(local_join(target, "nesteddir", "nestedfile")) - assert not local_fs.exists(local_join(target, "subdir")) - - local_fs.rm( - [ - local_join(target, "subfile1"), - local_join(target, "subfile2"), - ], - recursive=True, - ) - assert local_fs.ls(target) == [] - - # With recursive - for glob, recursive in zip(["*", "**"], [True, False]): - fs.get(fs_join(source, "subdir", glob), t, recursive=recursive) - assert local_fs.isfile(local_join(target, "subfile1")) - assert local_fs.isfile(local_join(target, "subfile2")) - assert local_fs.isdir(local_join(target, "nesteddir")) - assert local_fs.isfile(local_join(target, "nesteddir", "nestedfile")) - assert not local_fs.exists(local_join(target, "subdir")) - - local_fs.rm( - [ - local_join(target, "subfile1"), - local_join(target, "subfile2"), - local_join(target, "nesteddir"), - ], - recursive=True, - ) - assert local_fs.ls(target) == [] - - # Limit recursive by maxdepth - fs.get( - fs_join(source, "subdir", glob), t, recursive=recursive, maxdepth=1 - ) - assert local_fs.isfile(local_join(target, "subfile1")) - assert local_fs.isfile(local_join(target, "subfile2")) - assert not local_fs.exists(local_join(target, "nesteddir")) - assert not local_fs.exists(local_join(target, "subdir")) - - local_fs.rm( - [ - local_join(target, "subfile1"), - local_join(target, "subfile2"), - ], - recursive=True, - ) - assert local_fs.ls(target) == [] - - def test_get_glob_to_new_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1h - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - for target_slash in [False, True]: - t = fs_join(target, "newdir") - if target_slash: - t += "/" - - # Without recursive - fs.get(fs_join(source, "subdir", "*"), t) - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "subfile1")) - assert local_fs.isfile(local_join(target, "newdir", "subfile2")) - assert not local_fs.exists(local_join(target, "newdir", "nesteddir")) - assert not local_fs.exists( - local_join(target, "newdir", "nesteddir", "nestedfile") - ) - assert not local_fs.exists(local_join(target, "subdir")) - assert not local_fs.exists(local_join(target, "newdir", "subdir")) - - local_fs.rm(local_join(target, "newdir"), recursive=True) - assert local_fs.ls(target) == [] - - # With recursive - for glob, recursive in zip(["*", "**"], [True, False]): - fs.get(fs_join(source, "subdir", glob), t, recursive=recursive) - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "subfile1")) - assert local_fs.isfile(local_join(target, "newdir", "subfile2")) - assert local_fs.isdir(local_join(target, "newdir", "nesteddir")) - assert local_fs.isfile( - local_join(target, "newdir", "nesteddir", "nestedfile") - ) - assert not local_fs.exists(local_join(target, "subdir")) - assert not local_fs.exists(local_join(target, "newdir", "subdir")) - - local_fs.rm(local_join(target, "newdir"), recursive=True) - assert not local_fs.exists(local_join(target, "newdir")) - - # Limit recursive by maxdepth - fs.get( - fs_join(source, "subdir", glob), t, recursive=recursive, maxdepth=1 - ) - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "subfile1")) - assert local_fs.isfile(local_join(target, "newdir", "subfile2")) - assert not local_fs.exists(local_join(target, "newdir", "nesteddir")) - assert not local_fs.exists(local_join(target, "subdir")) - assert not local_fs.exists(local_join(target, "newdir", "subdir")) - - local_fs.rm(local_fs.ls(target, detail=False), recursive=True) - assert not local_fs.exists(local_join(target, "newdir")) - - @pytest.mark.parametrize( - GLOB_EDGE_CASES_TESTS["argnames"], - GLOB_EDGE_CASES_TESTS["argvalues"], - ) - def test_get_glob_edge_cases( - self, - path, - recursive, - maxdepth, - expected, - fs, - fs_join, - fs_glob_edge_cases_files, - local_fs, - local_join, - local_target, - ): - # Copy scenario 1g - source = fs_glob_edge_cases_files - - target = local_target - - for new_dir, target_slash in product([True, False], [True, False]): - local_fs.mkdir(target) - - t = local_join(target, "newdir") if new_dir else target - t = t + "/" if target_slash else t - - fs.get(fs_join(source, path), t, recursive=recursive, maxdepth=maxdepth) - - output = local_fs.find(target) - if new_dir: - prefixed_expected = [ - make_path_posix(local_join(target, "newdir", p)) for p in expected - ] - else: - prefixed_expected = [ - make_path_posix(local_join(target, p)) for p in expected - ] - assert sorted(output) == sorted(prefixed_expected) - - try: - local_fs.rm(target, recursive=True) - except FileNotFoundError: - pass - - def test_get_list_of_files_to_existing_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 2a - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - source_files = [ - fs_join(source, "file1"), - fs_join(source, "file2"), - fs_join(source, "subdir", "subfile1"), - ] - - for target_slash in [False, True]: - t = target + "/" if target_slash else target - - fs.get(source_files, t) - assert local_fs.isfile(local_join(target, "file1")) - assert local_fs.isfile(local_join(target, "file2")) - assert local_fs.isfile(local_join(target, "subfile1")) - - local_fs.rm( - [ - local_join(target, "file1"), - local_join(target, "file2"), - local_join(target, "subfile1"), - ], - recursive=True, - ) - assert local_fs.ls(target) == [] - - def test_get_list_of_files_to_new_directory( - self, - fs, - fs_join, - fs_bulk_operations_scenario_0, - local_fs, - local_join, - local_target, - ): - # Copy scenario 2b - source = fs_bulk_operations_scenario_0 - - target = local_target - local_fs.mkdir(target) - - source_files = [ - fs_join(source, "file1"), - fs_join(source, "file2"), - fs_join(source, "subdir", "subfile1"), - ] - - fs.get(source_files, local_join(target, "newdir") + "/") # Note trailing slash - assert local_fs.isdir(local_join(target, "newdir")) - assert local_fs.isfile(local_join(target, "newdir", "file1")) - assert local_fs.isfile(local_join(target, "newdir", "file2")) - assert local_fs.isfile(local_join(target, "newdir", "subfile1")) - - def test_get_directory_recursive( - self, fs, fs_join, fs_path, local_fs, local_join, local_target - ): - # https://github.com/fsspec/filesystem_spec/issues/1062 - # Recursive cp/get/put of source directory into non-existent target directory. - src = fs_join(fs_path, "src") - src_file = fs_join(src, "file") - fs.mkdir(src) - fs.touch(src_file) - - target = local_target - - # get without slash - assert not local_fs.exists(target) - for loop in range(2): - fs.get(src, target, recursive=True) - assert local_fs.isdir(target) - - if loop == 0: - assert local_fs.isfile(local_join(target, "file")) - assert not local_fs.exists(local_join(target, "src")) - else: - assert local_fs.isfile(local_join(target, "file")) - assert local_fs.isdir(local_join(target, "src")) - assert local_fs.isfile(local_join(target, "src", "file")) - - local_fs.rm(target, recursive=True) - - # get with slash - assert not local_fs.exists(target) - for loop in range(2): - fs.get(src + "/", target, recursive=True) - assert local_fs.isdir(target) - assert local_fs.isfile(local_join(target, "file")) - assert not local_fs.exists(local_join(target, "src")) - - def test_get_directory_without_files_with_same_name_prefix( - self, - fs, - fs_join, - local_fs, - local_join, - local_target, - fs_dir_and_file_with_same_name_prefix, - ): - # Create the test dirs - source = fs_dir_and_file_with_same_name_prefix - target = local_target - - # Test without glob - fs.get(fs_join(source, "subdir"), target, recursive=True) - - assert local_fs.isfile(local_join(target, "subfile.txt")) - assert not local_fs.isfile(local_join(target, "subdir.txt")) - - local_fs.rm([local_join(target, "subfile.txt")]) - assert local_fs.ls(target) == [] - - # Test with glob - fs.get(fs_join(source, "subdir*"), target, recursive=True) - - assert local_fs.isdir(local_join(target, "subdir")) - assert local_fs.isfile(local_join(target, "subdir", "subfile.txt")) - assert local_fs.isfile(local_join(target, "subdir.txt")) - - def test_get_with_source_and_destination_as_list( - self, - fs, - fs_join, - local_fs, - local_join, - local_target, - fs_10_files_with_hashed_names, - ): - # Create the test dir - source = fs_10_files_with_hashed_names - target = local_target - - # Create list of files for source and destination - source_files = [] - destination_files = [] - for i in range(10): - hashed_i = md5(str(i).encode("utf-8")).hexdigest() - source_files.append(fs_join(source, f"{hashed_i}.txt")) - destination_files.append( - make_path_posix(local_join(target, f"{hashed_i}.txt")) - ) - - # Copy and assert order was kept - fs.get(rpath=source_files, lpath=destination_files) - - for i in range(10): - file_content = local_fs.cat(destination_files[i]).decode("utf-8") - assert file_content == str(i) diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/mv.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/mv.py deleted file mode 100644 index 39f6caa3de815e024fa84de2acecc986c823ed29..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/mv.py +++ /dev/null @@ -1,57 +0,0 @@ -import os - -import pytest - -import fsspec - - -def test_move_raises_error_with_tmpdir(tmpdir): - # Create a file in the temporary directory - source = tmpdir.join("source_file.txt") - source.write("content") - - # Define a destination that simulates a protected or invalid path - destination = tmpdir.join("non_existent_directory/destination_file.txt") - - # Instantiate the filesystem (assuming the local file system interface) - fs = fsspec.filesystem("file") - - # Use the actual file paths as string - with pytest.raises(FileNotFoundError): - fs.mv(str(source), str(destination)) - - -@pytest.mark.parametrize("recursive", (True, False)) -def test_move_raises_error_with_tmpdir_permission(recursive, tmpdir): - # Create a file in the temporary directory - source = tmpdir.join("source_file.txt") - source.write("content") - - # Create a protected directory (non-writable) - protected_dir = tmpdir.mkdir("protected_directory") - protected_path = str(protected_dir) - - # Set the directory to read-only - if os.name == "nt": - os.system(f'icacls "{protected_path}" /deny Everyone:(W)') - else: - os.chmod(protected_path, 0o555) # Sets the directory to read-only - - # Define a destination inside the protected directory - destination = protected_dir.join("destination_file.txt") - - # Instantiate the filesystem (assuming the local file system interface) - fs = fsspec.filesystem("file") - - # Try to move the file to the read-only directory, expecting a permission error - with pytest.raises(PermissionError): - fs.mv(str(source), str(destination), recursive=recursive) - - # Assert the file was not created in the destination - assert not os.path.exists(destination) - - # Cleanup: Restore permissions so the directory can be cleaned up - if os.name == "nt": - os.system(f'icacls "{protected_path}" /remove:d Everyone') - else: - os.chmod(protected_path, 0o755) # Restore write permission for cleanup diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/open.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/open.py deleted file mode 100644 index bb75ea852276fb8d834345883813b8e27a0ae24c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/open.py +++ /dev/null @@ -1,11 +0,0 @@ -import pytest - - -class AbstractOpenTests: - def test_open_exclusive(self, fs, fs_target): - with fs.open(fs_target, "wb") as f: - f.write(b"data") - with fs.open(fs_target, "rb") as f: - assert f.read() == b"data" - with pytest.raises(FileExistsError): - fs.open(fs_target, "xb") diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/pipe.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/pipe.py deleted file mode 100644 index 8ecca96e9d23ff268a253c48269d5cca451ea270..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/pipe.py +++ /dev/null @@ -1,11 +0,0 @@ -import pytest - - -class AbstractPipeTests: - def test_pipe_exclusive(self, fs, fs_target): - fs.pipe_file(fs_target, b"data") - assert fs.cat_file(fs_target) == b"data" - with pytest.raises(FileExistsError): - fs.pipe_file(fs_target, b"data", mode="create") - fs.pipe_file(fs_target, b"new data", mode="overwrite") - assert fs.cat_file(fs_target) == b"new data" diff --git a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/put.py b/venv/lib/python3.10/site-packages/fsspec/tests/abstract/put.py deleted file mode 100644 index 9fc349977f0384d9fc86126498be5c6ad99a21d3..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/tests/abstract/put.py +++ /dev/null @@ -1,591 +0,0 @@ -from hashlib import md5 -from itertools import product - -import pytest - -from fsspec.tests.abstract.common import GLOB_EDGE_CASES_TESTS - - -class AbstractPutTests: - def test_put_file_to_existing_directory( - self, - fs, - fs_join, - fs_target, - local_join, - local_bulk_operations_scenario_0, - supports_empty_directories, - ): - # Copy scenario 1a - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - fs.touch(fs_join(target, "dummy")) - assert fs.isdir(target) - - target_file2 = fs_join(target, "file2") - target_subfile1 = fs_join(target, "subfile1") - - # Copy from source directory - fs.put(local_join(source, "file2"), target) - assert fs.isfile(target_file2) - - # Copy from sub directory - fs.put(local_join(source, "subdir", "subfile1"), target) - assert fs.isfile(target_subfile1) - - # Remove copied files - fs.rm([target_file2, target_subfile1]) - assert not fs.exists(target_file2) - assert not fs.exists(target_subfile1) - - # Repeat with trailing slash on target - fs.put(local_join(source, "file2"), target + "/") - assert fs.isdir(target) - assert fs.isfile(target_file2) - - fs.put(local_join(source, "subdir", "subfile1"), target + "/") - assert fs.isfile(target_subfile1) - - def test_put_file_to_new_directory( - self, fs, fs_join, fs_target, local_join, local_bulk_operations_scenario_0 - ): - # Copy scenario 1b - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - fs.put( - local_join(source, "subdir", "subfile1"), fs_join(target, "newdir/") - ) # Note trailing slash - assert fs.isdir(target) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - - def test_put_file_to_file_in_existing_directory( - self, - fs, - fs_join, - fs_target, - local_join, - supports_empty_directories, - local_bulk_operations_scenario_0, - ): - # Copy scenario 1c - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - fs.touch(fs_join(target, "dummy")) - assert fs.isdir(target) - - fs.put(local_join(source, "subdir", "subfile1"), fs_join(target, "newfile")) - assert fs.isfile(fs_join(target, "newfile")) - - def test_put_file_to_file_in_new_directory( - self, fs, fs_join, fs_target, local_join, local_bulk_operations_scenario_0 - ): - # Copy scenario 1d - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - fs.put( - local_join(source, "subdir", "subfile1"), - fs_join(target, "newdir", "newfile"), - ) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "newfile")) - - def test_put_directory_to_existing_directory( - self, - fs, - fs_join, - fs_target, - local_bulk_operations_scenario_0, - supports_empty_directories, - ): - # Copy scenario 1e - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - dummy = fs_join(target, "dummy") - fs.touch(dummy) - assert fs.isdir(target) - - for source_slash, target_slash in zip([False, True], [False, True]): - s = fs_join(source, "subdir") - if source_slash: - s += "/" - t = target + "/" if target_slash else target - - # Without recursive does nothing - fs.put(s, t) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # With recursive - fs.put(s, t, recursive=True) - if source_slash: - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert fs.isdir(fs_join(target, "nesteddir")) - assert fs.isfile(fs_join(target, "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - fs_join(target, "nesteddir"), - ], - recursive=True, - ) - else: - assert fs.isdir(fs_join(target, "subdir")) - assert fs.isfile(fs_join(target, "subdir", "subfile1")) - assert fs.isfile(fs_join(target, "subdir", "subfile2")) - assert fs.isdir(fs_join(target, "subdir", "nesteddir")) - assert fs.isfile(fs_join(target, "subdir", "nesteddir", "nestedfile")) - - fs.rm(fs_join(target, "subdir"), recursive=True) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # Limit recursive by maxdepth - fs.put(s, t, recursive=True, maxdepth=1) - if source_slash: - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert not fs.exists(fs_join(target, "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - ], - recursive=True, - ) - else: - assert fs.isdir(fs_join(target, "subdir")) - assert fs.isfile(fs_join(target, "subdir", "subfile1")) - assert fs.isfile(fs_join(target, "subdir", "subfile2")) - assert not fs.exists(fs_join(target, "subdir", "nesteddir")) - - fs.rm(fs_join(target, "subdir"), recursive=True) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - def test_put_directory_to_new_directory( - self, - fs, - fs_join, - fs_target, - local_bulk_operations_scenario_0, - supports_empty_directories, - ): - # Copy scenario 1f - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - for source_slash, target_slash in zip([False, True], [False, True]): - s = fs_join(source, "subdir") - if source_slash: - s += "/" - t = fs_join(target, "newdir") - if target_slash: - t += "/" - - # Without recursive does nothing - fs.put(s, t) - if supports_empty_directories: - assert fs.ls(target) == [] - else: - with pytest.raises(FileNotFoundError): - fs.ls(target) - - # With recursive - fs.put(s, t, recursive=True) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert fs.isdir(fs_join(target, "newdir", "nesteddir")) - assert fs.isfile(fs_join(target, "newdir", "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - # Limit recursive by maxdepth - fs.put(s, t, recursive=True, maxdepth=1) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - def test_put_glob_to_existing_directory( - self, - fs, - fs_join, - fs_target, - local_join, - supports_empty_directories, - local_bulk_operations_scenario_0, - ): - # Copy scenario 1g - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - dummy = fs_join(target, "dummy") - fs.touch(dummy) - assert fs.isdir(target) - - for target_slash in [False, True]: - t = target + "/" if target_slash else target - - # Without recursive - fs.put(local_join(source, "subdir", "*"), t) - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert not fs.isdir(fs_join(target, "nesteddir")) - assert not fs.exists(fs_join(target, "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # With recursive - for glob, recursive in zip(["*", "**"], [True, False]): - fs.put(local_join(source, "subdir", glob), t, recursive=recursive) - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert fs.isdir(fs_join(target, "nesteddir")) - assert fs.isfile(fs_join(target, "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - fs_join(target, "nesteddir"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - # Limit recursive by maxdepth - fs.put( - local_join(source, "subdir", glob), - t, - recursive=recursive, - maxdepth=1, - ) - assert fs.isfile(fs_join(target, "subfile1")) - assert fs.isfile(fs_join(target, "subfile2")) - assert not fs.exists(fs_join(target, "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - - fs.rm( - [ - fs_join(target, "subfile1"), - fs_join(target, "subfile2"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - def test_put_glob_to_new_directory( - self, fs, fs_join, fs_target, local_join, local_bulk_operations_scenario_0 - ): - # Copy scenario 1h - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - for target_slash in [False, True]: - t = fs_join(target, "newdir") - if target_slash: - t += "/" - - # Without recursive - fs.put(local_join(source, "subdir", "*"), t) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - assert not fs.exists(fs_join(target, "newdir", "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - # With recursive - for glob, recursive in zip(["*", "**"], [True, False]): - fs.put(local_join(source, "subdir", glob), t, recursive=recursive) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert fs.isdir(fs_join(target, "newdir", "nesteddir")) - assert fs.isfile(fs_join(target, "newdir", "nesteddir", "nestedfile")) - assert not fs.exists(fs_join(target, "subdir")) - assert not fs.exists(fs_join(target, "newdir", "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - # Limit recursive by maxdepth - fs.put( - local_join(source, "subdir", glob), - t, - recursive=recursive, - maxdepth=1, - ) - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - assert fs.isfile(fs_join(target, "newdir", "subfile2")) - assert not fs.exists(fs_join(target, "newdir", "nesteddir")) - assert not fs.exists(fs_join(target, "subdir")) - assert not fs.exists(fs_join(target, "newdir", "subdir")) - - fs.rm(fs_join(target, "newdir"), recursive=True) - assert not fs.exists(fs_join(target, "newdir")) - - @pytest.mark.parametrize( - GLOB_EDGE_CASES_TESTS["argnames"], - GLOB_EDGE_CASES_TESTS["argvalues"], - ) - def test_put_glob_edge_cases( - self, - path, - recursive, - maxdepth, - expected, - fs, - fs_join, - fs_target, - local_glob_edge_cases_files, - local_join, - fs_sanitize_path, - ): - # Copy scenario 1g - source = local_glob_edge_cases_files - - target = fs_target - - for new_dir, target_slash in product([True, False], [True, False]): - fs.mkdir(target) - - t = fs_join(target, "newdir") if new_dir else target - t = t + "/" if target_slash else t - - fs.put(local_join(source, path), t, recursive=recursive, maxdepth=maxdepth) - - output = fs.find(target) - if new_dir: - prefixed_expected = [ - fs_sanitize_path(fs_join(target, "newdir", p)) for p in expected - ] - else: - prefixed_expected = [ - fs_sanitize_path(fs_join(target, p)) for p in expected - ] - assert sorted(output) == sorted(prefixed_expected) - - try: - fs.rm(target, recursive=True) - except FileNotFoundError: - pass - - def test_put_list_of_files_to_existing_directory( - self, - fs, - fs_join, - fs_target, - local_join, - local_bulk_operations_scenario_0, - supports_empty_directories, - ): - # Copy scenario 2a - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - if not supports_empty_directories: - # Force target directory to exist by adding a dummy file - dummy = fs_join(target, "dummy") - fs.touch(dummy) - assert fs.isdir(target) - - source_files = [ - local_join(source, "file1"), - local_join(source, "file2"), - local_join(source, "subdir", "subfile1"), - ] - - for target_slash in [False, True]: - t = target + "/" if target_slash else target - - fs.put(source_files, t) - assert fs.isfile(fs_join(target, "file1")) - assert fs.isfile(fs_join(target, "file2")) - assert fs.isfile(fs_join(target, "subfile1")) - - fs.rm( - [ - fs_join(target, "file1"), - fs_join(target, "file2"), - fs_join(target, "subfile1"), - ], - recursive=True, - ) - assert fs.ls(target, detail=False) == ( - [] if supports_empty_directories else [dummy] - ) - - def test_put_list_of_files_to_new_directory( - self, fs, fs_join, fs_target, local_join, local_bulk_operations_scenario_0 - ): - # Copy scenario 2b - source = local_bulk_operations_scenario_0 - - target = fs_target - fs.mkdir(target) - - source_files = [ - local_join(source, "file1"), - local_join(source, "file2"), - local_join(source, "subdir", "subfile1"), - ] - - fs.put(source_files, fs_join(target, "newdir") + "/") # Note trailing slash - assert fs.isdir(fs_join(target, "newdir")) - assert fs.isfile(fs_join(target, "newdir", "file1")) - assert fs.isfile(fs_join(target, "newdir", "file2")) - assert fs.isfile(fs_join(target, "newdir", "subfile1")) - - def test_put_directory_recursive( - self, fs, fs_join, fs_target, local_fs, local_join, local_path - ): - # https://github.com/fsspec/filesystem_spec/issues/1062 - # Recursive cp/get/put of source directory into non-existent target directory. - src = local_join(local_path, "src") - src_file = local_join(src, "file") - local_fs.mkdir(src) - local_fs.touch(src_file) - - target = fs_target - - # put without slash - assert not fs.exists(target) - for loop in range(2): - fs.put(src, target, recursive=True) - assert fs.isdir(target) - - if loop == 0: - assert fs.isfile(fs_join(target, "file")) - assert not fs.exists(fs_join(target, "src")) - else: - assert fs.isfile(fs_join(target, "file")) - assert fs.isdir(fs_join(target, "src")) - assert fs.isfile(fs_join(target, "src", "file")) - - fs.rm(target, recursive=True) - - # put with slash - assert not fs.exists(target) - for loop in range(2): - fs.put(src + "/", target, recursive=True) - assert fs.isdir(target) - assert fs.isfile(fs_join(target, "file")) - assert not fs.exists(fs_join(target, "src")) - - def test_put_directory_without_files_with_same_name_prefix( - self, - fs, - fs_join, - fs_target, - local_join, - local_dir_and_file_with_same_name_prefix, - supports_empty_directories, - ): - # Create the test dirs - source = local_dir_and_file_with_same_name_prefix - target = fs_target - - # Test without glob - fs.put(local_join(source, "subdir"), fs_target, recursive=True) - - assert fs.isfile(fs_join(fs_target, "subfile.txt")) - assert not fs.isfile(fs_join(fs_target, "subdir.txt")) - - fs.rm([fs_join(target, "subfile.txt")]) - if supports_empty_directories: - assert fs.ls(target) == [] - else: - assert not fs.exists(target) - - # Test with glob - fs.put(local_join(source, "subdir*"), fs_target, recursive=True) - - assert fs.isdir(fs_join(fs_target, "subdir")) - assert fs.isfile(fs_join(fs_target, "subdir", "subfile.txt")) - assert fs.isfile(fs_join(fs_target, "subdir.txt")) - - def test_copy_with_source_and_destination_as_list( - self, fs, fs_target, fs_join, local_join, local_10_files_with_hashed_names - ): - # Create the test dir - source = local_10_files_with_hashed_names - target = fs_target - - # Create list of files for source and destination - source_files = [] - destination_files = [] - for i in range(10): - hashed_i = md5(str(i).encode("utf-8")).hexdigest() - source_files.append(local_join(source, f"{hashed_i}.txt")) - destination_files.append(fs_join(target, f"{hashed_i}.txt")) - - # Copy and assert order was kept - fs.put(lpath=source_files, rpath=destination_files) - - for i in range(10): - file_content = fs.cat(destination_files[i]).decode("utf-8") - assert file_content == str(i) diff --git a/venv/lib/python3.10/site-packages/fsspec/transaction.py b/venv/lib/python3.10/site-packages/fsspec/transaction.py deleted file mode 100644 index 77293f63ecc5f611e19d849ef236d53e9c258efc..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/transaction.py +++ /dev/null @@ -1,90 +0,0 @@ -from collections import deque - - -class Transaction: - """Filesystem transaction write context - - Gathers files for deferred commit or discard, so that several write - operations can be finalized semi-atomically. This works by having this - instance as the ``.transaction`` attribute of the given filesystem - """ - - def __init__(self, fs, **kwargs): - """ - Parameters - ---------- - fs: FileSystem instance - """ - self.fs = fs - self.files = deque() - - def __enter__(self): - self.start() - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - """End transaction and commit, if exit is not due to exception""" - # only commit if there was no exception - self.complete(commit=exc_type is None) - if self.fs: - self.fs._intrans = False - self.fs._transaction = None - self.fs = None - - def start(self): - """Start a transaction on this FileSystem""" - self.files = deque() # clean up after previous failed completions - self.fs._intrans = True - - def complete(self, commit=True): - """Finish transaction: commit or discard all deferred files""" - while self.files: - f = self.files.popleft() - if commit: - f.commit() - else: - f.discard() - self.fs._intrans = False - self.fs._transaction = None - self.fs = None - - -class FileActor: - def __init__(self): - self.files = [] - - def commit(self): - for f in self.files: - f.commit() - self.files.clear() - - def discard(self): - for f in self.files: - f.discard() - self.files.clear() - - def append(self, f): - self.files.append(f) - - -class DaskTransaction(Transaction): - def __init__(self, fs): - """ - Parameters - ---------- - fs: FileSystem instance - """ - import distributed - - super().__init__(fs) - client = distributed.default_client() - self.files = client.submit(FileActor, actor=True).result() - - def complete(self, commit=True): - """Finish transaction: commit or discard all deferred files""" - if commit: - self.files.commit().result() - else: - self.files.discard().result() - self.fs._intrans = False - self.fs = None diff --git a/venv/lib/python3.10/site-packages/fsspec/utils.py b/venv/lib/python3.10/site-packages/fsspec/utils.py deleted file mode 100644 index 7b06dd581417eca1e90a19ef25fb14dcd3cf9c9c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/fsspec/utils.py +++ /dev/null @@ -1,748 +0,0 @@ -from __future__ import annotations - -import contextlib -import logging -import math -import os -import re -import sys -import tempfile -from collections.abc import Callable, Iterable, Iterator, Sequence -from functools import partial -from hashlib import md5 -from importlib.metadata import version -from typing import IO, TYPE_CHECKING, Any, TypeVar -from urllib.parse import urlsplit - -if TYPE_CHECKING: - import pathlib - from typing import TypeGuard - - from fsspec.spec import AbstractFileSystem - - -DEFAULT_BLOCK_SIZE = 5 * 2**20 - -T = TypeVar("T") - - -def infer_storage_options( - urlpath: str, inherit_storage_options: dict[str, Any] | None = None -) -> dict[str, Any]: - """Infer storage options from URL path and merge it with existing storage - options. - - Parameters - ---------- - urlpath: str or unicode - Either local absolute file path or URL (hdfs://namenode:8020/file.csv) - inherit_storage_options: dict (optional) - Its contents will get merged with the inferred information from the - given path - - Returns - ------- - Storage options dict. - - Examples - -------- - >>> infer_storage_options('/mnt/datasets/test.csv') # doctest: +SKIP - {"protocol": "file", "path", "/mnt/datasets/test.csv"} - >>> infer_storage_options( - ... 'hdfs://username:pwd@node:123/mnt/datasets/test.csv?q=1', - ... inherit_storage_options={'extra': 'value'}, - ... ) # doctest: +SKIP - {"protocol": "hdfs", "username": "username", "password": "pwd", - "host": "node", "port": 123, "path": "/mnt/datasets/test.csv", - "url_query": "q=1", "extra": "value"} - """ - # Handle Windows paths including disk name in this special case - if ( - re.match(r"^[a-zA-Z]:[\\/]", urlpath) - or re.match(r"^[a-zA-Z0-9]+://", urlpath) is None - ): - return {"protocol": "file", "path": urlpath} - - parsed_path = urlsplit(urlpath) - protocol = parsed_path.scheme or "file" - if parsed_path.fragment: - path = "#".join([parsed_path.path, parsed_path.fragment]) - else: - path = parsed_path.path - if protocol == "file": - # Special case parsing file protocol URL on Windows according to: - # https://msdn.microsoft.com/en-us/library/jj710207.aspx - windows_path = re.match(r"^/([a-zA-Z])[:|]([\\/].*)$", path) - if windows_path: - drive, path = windows_path.groups() - path = f"{drive}:{path}" - - if protocol in ["http", "https"]: - # for HTTP, we don't want to parse, as requests will anyway - return {"protocol": protocol, "path": urlpath} - - options: dict[str, Any] = {"protocol": protocol, "path": path} - - if parsed_path.netloc: - # Parse `hostname` from netloc manually because `parsed_path.hostname` - # lowercases the hostname which is not always desirable (e.g. in S3): - # https://github.com/dask/dask/issues/1417 - options["host"] = parsed_path.netloc.rsplit("@", 1)[-1].rsplit(":", 1)[0] - - if protocol in ("s3", "s3a", "gcs", "gs"): - options["path"] = options["host"] + options["path"] - else: - options["host"] = options["host"] - if parsed_path.port: - options["port"] = parsed_path.port - if parsed_path.username: - options["username"] = parsed_path.username - if parsed_path.password: - options["password"] = parsed_path.password - - if parsed_path.query: - options["url_query"] = parsed_path.query - if parsed_path.fragment: - options["url_fragment"] = parsed_path.fragment - - if inherit_storage_options: - update_storage_options(options, inherit_storage_options) - - return options - - -def update_storage_options( - options: dict[str, Any], inherited: dict[str, Any] | None = None -) -> None: - if not inherited: - inherited = {} - collisions = set(options) & set(inherited) - if collisions: - for collision in collisions: - if options.get(collision) != inherited.get(collision): - raise KeyError( - f"Collision between inferred and specified storage " - f"option:\n{collision}" - ) - options.update(inherited) - - -# Compression extensions registered via fsspec.compression.register_compression -compressions: dict[str, str] = {} - - -def infer_compression(filename: str) -> str | None: - """Infer compression, if available, from filename. - - Infer a named compression type, if registered and available, from filename - extension. This includes builtin (gz, bz2, zip) compressions, as well as - optional compressions. See fsspec.compression.register_compression. - """ - extension = os.path.splitext(filename)[-1].strip(".").lower() - if extension in compressions: - return compressions[extension] - return None - - -def build_name_function(max_int: float) -> Callable[[int], str]: - """Returns a function that receives a single integer - and returns it as a string padded by enough zero characters - to align with maximum possible integer - - >>> name_f = build_name_function(57) - - >>> name_f(7) - '07' - >>> name_f(31) - '31' - >>> build_name_function(1000)(42) - '0042' - >>> build_name_function(999)(42) - '042' - >>> build_name_function(0)(0) - '0' - """ - # handle corner cases max_int is 0 or exact power of 10 - max_int += 1e-8 - - pad_length = int(math.ceil(math.log10(max_int))) - - def name_function(i: int) -> str: - return str(i).zfill(pad_length) - - return name_function - - -def seek_delimiter(file: IO[bytes], delimiter: bytes, blocksize: int) -> bool: - r"""Seek current file to file start, file end, or byte after delimiter seq. - - Seeks file to next chunk delimiter, where chunks are defined on file start, - a delimiting sequence, and file end. Use file.tell() to see location afterwards. - Note that file start is a valid split, so must be at offset > 0 to seek for - delimiter. - - Parameters - ---------- - file: a file - delimiter: bytes - a delimiter like ``b'\n'`` or message sentinel, matching file .read() type - blocksize: int - Number of bytes to read from the file at once. - - - Returns - ------- - Returns True if a delimiter was found, False if at file start or end. - - """ - - if file.tell() == 0: - # beginning-of-file, return without seek - return False - - # Interface is for binary IO, with delimiter as bytes, but initialize last - # with result of file.read to preserve compatibility with text IO. - last: bytes | None = None - while True: - current = file.read(blocksize) - if not current: - # end-of-file without delimiter - return False - full = last + current if last else current - try: - if delimiter in full: - i = full.index(delimiter) - file.seek(file.tell() - (len(full) - i) + len(delimiter)) - return True - elif len(current) < blocksize: - # end-of-file without delimiter - return False - except (OSError, ValueError): - pass - last = full[-len(delimiter) :] - - -def read_block( - f: IO[bytes], - offset: int, - length: int | None, - delimiter: bytes | None = None, - split_before: bool = False, -) -> bytes: - """Read a block of bytes from a file - - Parameters - ---------- - f: File - Open file - offset: int - Byte offset to start read - length: int - Number of bytes to read, read through end of file if None - delimiter: bytes (optional) - Ensure reading starts and stops at delimiter bytestring - split_before: bool (optional) - Start/stop read *before* delimiter bytestring. - - - If using the ``delimiter=`` keyword argument we ensure that the read - starts and stops at delimiter boundaries that follow the locations - ``offset`` and ``offset + length``. If ``offset`` is zero then we - start at zero, regardless of delimiter. The bytestring returned WILL - include the terminating delimiter string. - - Examples - -------- - - >>> from io import BytesIO # doctest: +SKIP - >>> f = BytesIO(b'Alice, 100\\nBob, 200\\nCharlie, 300') # doctest: +SKIP - >>> read_block(f, 0, 13) # doctest: +SKIP - b'Alice, 100\\nBo' - - >>> read_block(f, 0, 13, delimiter=b'\\n') # doctest: +SKIP - b'Alice, 100\\nBob, 200\\n' - - >>> read_block(f, 10, 10, delimiter=b'\\n') # doctest: +SKIP - b'Bob, 200\\nCharlie, 300' - """ - if delimiter: - f.seek(offset) - found_start_delim = seek_delimiter(f, delimiter, 2**16) - if length is None: - return f.read() - start = f.tell() - length -= start - offset - - f.seek(start + length) - found_end_delim = seek_delimiter(f, delimiter, 2**16) - end = f.tell() - - # Adjust split location to before delimiter if seek found the - # delimiter sequence, not start or end of file. - if found_start_delim and split_before: - start -= len(delimiter) - - if found_end_delim and split_before: - end -= len(delimiter) - - offset = start - length = end - start - - f.seek(offset) - - # TODO: allow length to be None and read to the end of the file? - assert length is not None - b = f.read(length) - return b - - -def tokenize(*args: Any, **kwargs: Any) -> str: - """Deterministic token - - (modified from dask.base) - - >>> tokenize([1, 2, '3']) - '9d71491b50023b06fc76928e6eddb952' - - >>> tokenize('Hello') == tokenize('Hello') - True - """ - if kwargs: - args += (kwargs,) - try: - h = md5(str(args).encode()) - except ValueError: - # FIPS systems: https://github.com/fsspec/filesystem_spec/issues/380 - h = md5(str(args).encode(), usedforsecurity=False) - return h.hexdigest() - - -def stringify_path(filepath: str | os.PathLike[str] | pathlib.Path) -> str: - """Attempt to convert a path-like object to a string. - - Parameters - ---------- - filepath: object to be converted - - Returns - ------- - filepath_str: maybe a string version of the object - - Notes - ----- - Objects supporting the fspath protocol are coerced according to its - __fspath__ method. - - For backwards compatibility with older Python version, pathlib.Path - objects are specially coerced. - - Any other object is passed through unchanged, which includes bytes, - strings, buffers, or anything else that's not even path-like. - """ - if isinstance(filepath, str): - return filepath - elif hasattr(filepath, "__fspath__"): - return filepath.__fspath__() - elif hasattr(filepath, "path"): - return filepath.path - else: - return filepath # type: ignore[return-value] - - -def make_instance( - cls: Callable[..., T], args: Sequence[Any], kwargs: dict[str, Any] -) -> T: - inst = cls(*args, **kwargs) - inst._determine_worker() # type: ignore[attr-defined] - return inst - - -def common_prefix(paths: Iterable[str]) -> str: - """For a list of paths, find the shortest prefix common to all""" - parts = [p.split("/") for p in paths] - lmax = min(len(p) for p in parts) - end = 0 - for i in range(lmax): - end = all(p[i] == parts[0][i] for p in parts) - if not end: - break - i += end - return "/".join(parts[0][:i]) - - -def other_paths( - paths: list[str], - path2: str | list[str], - exists: bool = False, - flatten: bool = False, -) -> list[str]: - """In bulk file operations, construct a new file tree from a list of files - - Parameters - ---------- - paths: list of str - The input file tree - path2: str or list of str - Root to construct the new list in. If this is already a list of str, we just - assert it has the right number of elements. - exists: bool (optional) - For a str destination, it is already exists (and is a dir), files should - end up inside. - flatten: bool (optional) - Whether to flatten the input directory tree structure so that the output files - are in the same directory. - - Returns - ------- - list of str - """ - - if isinstance(path2, str): - path2 = path2.rstrip("/") - - if flatten: - path2 = ["/".join((path2, p.split("/")[-1])) for p in paths] - else: - cp = common_prefix(paths) - if exists: - cp = cp.rsplit("/", 1)[0] - if not cp and all(not s.startswith("/") for s in paths): - path2 = ["/".join([path2, p]) for p in paths] - else: - path2 = [p.replace(cp, path2, 1) for p in paths] - else: - assert len(paths) == len(path2) - return path2 - - -def is_exception(obj: Any) -> bool: - return isinstance(obj, BaseException) - - -def isfilelike(f: Any) -> TypeGuard[IO[bytes]]: - return all(hasattr(f, attr) for attr in ["read", "close", "tell"]) - - -def get_protocol(url: str) -> str: - url = stringify_path(url) - parts = re.split(r"(\:\:|\://)", url, maxsplit=1) - if len(parts) > 1: - return parts[0] - return "file" - - -def get_file_extension(url: str) -> str: - url = stringify_path(url) - ext_parts = url.rsplit(".", 1) - if len(ext_parts) > 1: - return ext_parts[-1] - return "" - - -def can_be_local(path: str) -> bool: - """Can the given URL be used with open_local?""" - from fsspec import get_filesystem_class - - try: - return getattr(get_filesystem_class(get_protocol(path)), "local_file", False) - except (ValueError, ImportError): - # not in registry or import failed - return False - - -def get_package_version_without_import(name: str) -> str | None: - """For given package name, try to find the version without importing it - - Import and package.__version__ is still the backup here, so an import - *might* happen. - - Returns either the version string, or None if the package - or the version was not readily found. - """ - if name in sys.modules: - mod = sys.modules[name] - if hasattr(mod, "__version__"): - return mod.__version__ - try: - return version(name) - except: # noqa: E722 - pass - try: - import importlib - - mod = importlib.import_module(name) - return mod.__version__ - except (ImportError, AttributeError): - return None - - -def setup_logging( - logger: logging.Logger | None = None, - logger_name: str | None = None, - level: str = "DEBUG", - clear: bool = True, -) -> logging.Logger: - if logger is None and logger_name is None: - raise ValueError("Provide either logger object or logger name") - logger = logger or logging.getLogger(logger_name) - handle = logging.StreamHandler() - formatter = logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(funcName)s -- %(message)s" - ) - handle.setFormatter(formatter) - if clear: - logger.handlers.clear() - logger.addHandler(handle) - logger.setLevel(level) - return logger - - -def _unstrip_protocol(name: str, fs: AbstractFileSystem) -> str: - return fs.unstrip_protocol(name) - - -def mirror_from( - origin_name: str, methods: Iterable[str] -) -> Callable[[type[T]], type[T]]: - """Mirror attributes and methods from the given - origin_name attribute of the instance to the - decorated class""" - - def origin_getter(method: str, self: Any) -> Any: - origin = getattr(self, origin_name) - return getattr(origin, method) - - def wrapper(cls: type[T]) -> type[T]: - for method in methods: - wrapped_method = partial(origin_getter, method) - setattr(cls, method, property(wrapped_method)) - return cls - - return wrapper - - -@contextlib.contextmanager -def nullcontext(obj: T) -> Iterator[T]: - yield obj - - -def merge_offset_ranges( - paths: list[str], - starts: list[int] | int, - ends: list[int] | int, - max_gap: int = 0, - max_block: int | None = None, - sort: bool = True, -) -> tuple[list[str], list[int], list[int]]: - """Merge adjacent byte-offset ranges when the inter-range - gap is <= `max_gap`, and when the merged byte range does not - exceed `max_block` (if specified). By default, this function - will re-order the input paths and byte ranges to ensure sorted - order. If the user can guarantee that the inputs are already - sorted, passing `sort=False` will skip the re-ordering. - """ - # Check input - if not isinstance(paths, list): - raise TypeError - if not isinstance(starts, list): - starts = [starts] * len(paths) - if not isinstance(ends, list): - ends = [ends] * len(paths) - if len(starts) != len(paths) or len(ends) != len(paths): - raise ValueError - - # Early Return - if len(starts) <= 1: - return paths, starts, ends - - starts = [s or 0 for s in starts] - # Sort by paths and then ranges if `sort=True` - if sort: - paths, starts, ends = ( - list(v) - for v in zip( - *sorted( - zip(paths, starts, ends), - ) - ) - ) - remove = [] - for i, (path, start, end) in enumerate(zip(paths, starts, ends)): - if any( - e is not None and p == path and start >= s and end <= e and i != i2 - for i2, (p, s, e) in enumerate(zip(paths, starts, ends)) - ): - remove.append(i) - paths = [p for i, p in enumerate(paths) if i not in remove] - starts = [s for i, s in enumerate(starts) if i not in remove] - ends = [e for i, e in enumerate(ends) if i not in remove] - - if paths: - # Loop through the coupled `paths`, `starts`, and - # `ends`, and merge adjacent blocks when appropriate - new_paths = paths[:1] - new_starts = starts[:1] - new_ends = ends[:1] - for i in range(1, len(paths)): - if paths[i] == paths[i - 1] and new_ends[-1] is None: - continue - elif ( - paths[i] != paths[i - 1] - or ((starts[i] - new_ends[-1]) > max_gap) - or (max_block is not None and (ends[i] - new_starts[-1]) > max_block) - ): - # Cannot merge with previous block. - # Add new `paths`, `starts`, and `ends` elements - new_paths.append(paths[i]) - new_starts.append(starts[i]) - new_ends.append(ends[i]) - else: - # Merge with the previous block by updating the - # last element of `ends` - new_ends[-1] = ends[i] - return new_paths, new_starts, new_ends - - # `paths` is empty. Just return input lists - return paths, starts, ends - - -def file_size(filelike: IO[bytes]) -> int: - """Find length of any open read-mode file-like""" - pos = filelike.tell() - try: - return filelike.seek(0, 2) - finally: - filelike.seek(pos) - - -@contextlib.contextmanager -def atomic_write(path: str, mode: str = "wb"): - """ - A context manager that opens a temporary file next to `path` and, on exit, - replaces `path` with the temporary file, thereby updating `path` - atomically. - """ - fd, fn = tempfile.mkstemp( - dir=os.path.dirname(path), prefix=os.path.basename(path) + "-" - ) - try: - with open(fd, mode) as fp: - yield fp - except BaseException: - with contextlib.suppress(FileNotFoundError): - os.unlink(fn) - raise - else: - os.replace(fn, path) - - -def _translate(pat, STAR, QUESTION_MARK): - # Copied from: https://github.com/python/cpython/pull/106703. - res: list[str] = [] - add = res.append - i, n = 0, len(pat) - while i < n: - c = pat[i] - i = i + 1 - if c == "*": - # compress consecutive `*` into one - if (not res) or res[-1] is not STAR: - add(STAR) - elif c == "?": - add(QUESTION_MARK) - elif c == "[": - j = i - if j < n and pat[j] == "!": - j = j + 1 - if j < n and pat[j] == "]": - j = j + 1 - while j < n and pat[j] != "]": - j = j + 1 - if j >= n: - add("\\[") - else: - stuff = pat[i:j] - if "-" not in stuff: - stuff = stuff.replace("\\", r"\\") - else: - chunks = [] - k = i + 2 if pat[i] == "!" else i + 1 - while True: - k = pat.find("-", k, j) - if k < 0: - break - chunks.append(pat[i:k]) - i = k + 1 - k = k + 3 - chunk = pat[i:j] - if chunk: - chunks.append(chunk) - else: - chunks[-1] += "-" - # Remove empty ranges -- invalid in RE. - for k in range(len(chunks) - 1, 0, -1): - if chunks[k - 1][-1] > chunks[k][0]: - chunks[k - 1] = chunks[k - 1][:-1] + chunks[k][1:] - del chunks[k] - # Escape backslashes and hyphens for set difference (--). - # Hyphens that create ranges shouldn't be escaped. - stuff = "-".join( - s.replace("\\", r"\\").replace("-", r"\-") for s in chunks - ) - # Escape set operations (&&, ~~ and ||). - stuff = re.sub(r"([&~|])", r"\\\1", stuff) - i = j + 1 - if not stuff: - # Empty range: never match. - add("(?!)") - elif stuff == "!": - # Negated empty range: match any character. - add(".") - else: - if stuff[0] == "!": - stuff = "^" + stuff[1:] - elif stuff[0] in ("^", "["): - stuff = "\\" + stuff - add(f"[{stuff}]") - else: - add(re.escape(c)) - assert i == n - return res - - -def glob_translate(pat): - # Copied from: https://github.com/python/cpython/pull/106703. - # The keyword parameters' values are fixed to: - # recursive=True, include_hidden=True, seps=None - """Translate a pathname with shell wildcards to a regular expression.""" - if os.path.altsep: - seps = os.path.sep + os.path.altsep - else: - seps = os.path.sep - escaped_seps = "".join(map(re.escape, seps)) - any_sep = f"[{escaped_seps}]" if len(seps) > 1 else escaped_seps - not_sep = f"[^{escaped_seps}]" - one_last_segment = f"{not_sep}+" - one_segment = f"{one_last_segment}{any_sep}" - any_segments = f"(?:.+{any_sep})?" - any_last_segments = ".*" - results = [] - parts = re.split(any_sep, pat) - last_part_idx = len(parts) - 1 - for idx, part in enumerate(parts): - if part == "*": - results.append(one_segment if idx < last_part_idx else one_last_segment) - continue - if part == "**": - results.append(any_segments if idx < last_part_idx else any_last_segments) - continue - elif "**" in part: - raise ValueError( - "Invalid pattern: '**' can only be an entire path component" - ) - if part: - results.extend(_translate(part, f"{not_sep}*", not_sep)) - if idx < last_part_idx: - results.append(any_sep) - res = "".join(results) - return rf"(?s:{res})\Z" diff --git a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/METADATA b/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/METADATA deleted file mode 100644 index 8a2f639061cc4a203f7109d8335d28076442c61d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/METADATA +++ /dev/null @@ -1,202 +0,0 @@ -Metadata-Version: 2.4 -Name: h11 -Version: 0.16.0 -Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1 -Home-page: https://github.com/python-hyper/h11 -Author: Nathaniel J. Smith -Author-email: njs@pobox.com -License: MIT -Classifier: Development Status :: 3 - Alpha -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: System :: Networking -Requires-Python: >=3.8 -License-File: LICENSE.txt -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: license-file -Dynamic: requires-python -Dynamic: summary - -h11 -=== - -.. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master - :target: https://travis-ci.org/python-hyper/h11 - :alt: Automated test status - -.. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg - :target: https://codecov.io/gh/python-hyper/h11 - :alt: Test coverage - -.. image:: https://readthedocs.org/projects/h11/badge/?version=latest - :target: http://h11.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status - -This is a little HTTP/1.1 library written from scratch in Python, -heavily inspired by `hyper-h2 `_. - -It's a "bring-your-own-I/O" library; h11 contains no IO code -whatsoever. This means you can hook h11 up to your favorite network -API, and that could be anything you want: synchronous, threaded, -asynchronous, or your own implementation of `RFC 6214 -`_ -- h11 won't judge you. -(Compare this to the current state of the art, where every time a `new -network API `_ comes along then someone -gets to start over reimplementing the entire HTTP protocol from -scratch.) Cory Benfield made an `excellent blog post describing the -benefits of this approach -`_, or if you like video -then here's his `PyCon 2016 talk on the same theme -`_. - -This also means that h11 is not immediately useful out of the box: -it's a toolkit for building programs that speak HTTP, not something -that could directly replace ``requests`` or ``twisted.web`` or -whatever. But h11 makes it much easier to implement something like -``requests`` or ``twisted.web``. - -At a high level, working with h11 goes like this: - -1) First, create an ``h11.Connection`` object to track the state of a - single HTTP/1.1 connection. - -2) When you read data off the network, pass it to - ``conn.receive_data(...)``; you'll get back a list of objects - representing high-level HTTP "events". - -3) When you want to send a high-level HTTP event, create the - corresponding "event" object and pass it to ``conn.send(...)``; - this will give you back some bytes that you can then push out - through the network. - -For example, a client might instantiate and then send a -``h11.Request`` object, then zero or more ``h11.Data`` objects for the -request body (e.g., if this is a POST), and then a -``h11.EndOfMessage`` to indicate the end of the message. Then the -server would then send back a ``h11.Response``, some ``h11.Data``, and -its own ``h11.EndOfMessage``. If either side violates the protocol, -you'll get a ``h11.ProtocolError`` exception. - -h11 is suitable for implementing both servers and clients, and has a -pleasantly symmetric API: the events you send as a client are exactly -the ones that you receive as a server and vice-versa. - -`Here's an example of a tiny HTTP client -`_ - -It also has `a fine manual `_. - -FAQ ---- - -*Whyyyyy?* - -I wanted to play with HTTP in `Curio -`__ and `Trio -`__, which at the time didn't have any -HTTP libraries. So I thought, no big deal, Python has, like, a dozen -different implementations of HTTP, surely I can find one that's -reusable. I didn't find one, but I did find Cory's call-to-arms -blog-post. So I figured, well, fine, if I have to implement HTTP from -scratch, at least I can make sure no-one *else* has to ever again. - -*Should I use it?* - -Maybe. You should be aware that it's a very young project. But, it's -feature complete and has an exhaustive test-suite and complete docs, -so the next step is for people to try using it and see how it goes -:-). If you do then please let us know -- if nothing else we'll want -to talk to you before making any incompatible changes! - -*What are the features/limitations?* - -Roughly speaking, it's trying to be a robust, complete, and non-hacky -implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230: -HTTP/1.1 Message Syntax and Routing -`_. That is, it mostly focuses on -implementing HTTP at the level of taking bytes on and off the wire, -and the headers related to that, and tries to be anal about spec -conformance. It doesn't know about higher-level concerns like URL -routing, conditional GETs, cross-origin cookie policies, or content -negotiation. But it does know how to take care of framing, -cross-version differences in keep-alive handling, and the "obsolete -line folding" rule, so you can focus your energies on the hard / -interesting parts for your application, and it tries to support the -full specification in the sense that any useful HTTP/1.1 conformant -application should be able to use h11. - -It's pure Python, and has no dependencies outside of the standard -library. - -It has a test suite with 100.0% coverage for both statements and -branches. - -Currently it supports Python 3 (testing on 3.8-3.12) and PyPy 3. -The last Python 2-compatible version was h11 0.11.x. -(Originally it had a Cython wrapper for `http-parser -`_ and a beautiful nested state -machine implemented with ``yield from`` to postprocess the output. But -I had to take these out -- the new *parser* needs fewer lines-of-code -than the old *parser wrapper*, is written in pure Python, uses no -exotic language syntax, and has more features. It's sad, really; that -old state machine was really slick. I just need a few sentences here -to mourn that.) - -I don't know how fast it is. I haven't benchmarked or profiled it yet, -so it's probably got a few pointless hot spots, and I've been trying -to err on the side of simplicity and robustness instead of -micro-optimization. But at the architectural level I tried hard to -avoid fundamentally bad decisions, e.g., I believe that all the -parsing algorithms remain linear-time even in the face of pathological -input like slowloris, and there are no byte-by-byte loops. (I also -believe that it maintains bounded memory usage in the face of -arbitrary/pathological input.) - -The whole library is ~800 lines-of-code. You can read and understand -the whole thing in less than an hour. Most of the energy invested in -this so far has been spent on trying to keep things simple by -minimizing special-cases and ad hoc state manipulation; even though it -is now quite small and simple, I'm still annoyed that I haven't -figured out how to make it even smaller and simpler. (Unfortunately, -HTTP does not lend itself to simplicity.) - -The API is ~feature complete and I don't expect the general outlines -to change much, but you can't judge an API's ergonomics until you -actually document and use it, so I'd expect some changes in the -details. - -*How do I try it?* - -.. code-block:: sh - - $ pip install h11 - $ git clone git@github.com:python-hyper/h11 - $ cd h11/examples - $ python basic-client.py - -and go from there. - -*License?* - -MIT - -*Code of conduct?* - -Contributors are requested to follow our `code of conduct -`_ in -all project spaces. diff --git a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/RECORD b/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/RECORD deleted file mode 100644 index 43bafd33bdd5a47bcd27930886cfd95e3fd92562..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/RECORD +++ /dev/null @@ -1,29 +0,0 @@ -h11-0.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -h11-0.16.0.dist-info/METADATA,sha256=KPMmCYrAn8unm48YD5YIfIQf4kViFct7hyqcfVzRnWQ,8348 -h11-0.16.0.dist-info/RECORD,, -h11-0.16.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91 -h11-0.16.0.dist-info/licenses/LICENSE.txt,sha256=N9tbuFkm2yikJ6JYZ_ELEjIAOuob5pzLhRE4rbjm82E,1124 -h11-0.16.0.dist-info/top_level.txt,sha256=F7dC4jl3zeh8TGHEPaWJrMbeuoWbS379Gwdi-Yvdcis,4 -h11/__init__.py,sha256=iO1KzkSO42yZ6ffg-VMgbx_ZVTWGUY00nRYEWn-s3kY,1507 -h11/__pycache__/__init__.cpython-310.pyc,, -h11/__pycache__/_abnf.cpython-310.pyc,, -h11/__pycache__/_connection.cpython-310.pyc,, -h11/__pycache__/_events.cpython-310.pyc,, -h11/__pycache__/_headers.cpython-310.pyc,, -h11/__pycache__/_readers.cpython-310.pyc,, -h11/__pycache__/_receivebuffer.cpython-310.pyc,, -h11/__pycache__/_state.cpython-310.pyc,, -h11/__pycache__/_util.cpython-310.pyc,, -h11/__pycache__/_version.cpython-310.pyc,, -h11/__pycache__/_writers.cpython-310.pyc,, -h11/_abnf.py,sha256=ybixr0xsupnkA6GFAyMubuXF6Tc1lb_hF890NgCsfNc,4815 -h11/_connection.py,sha256=k9YRVf6koZqbttBW36xSWaJpWdZwa-xQVU9AHEo9DuI,26863 -h11/_events.py,sha256=I97aXoal1Wu7dkL548BANBUCkOIbe-x5CioYA9IBY14,11792 -h11/_headers.py,sha256=P7D-lBNxHwdLZPLimmYwrPG-9ZkjElvvJZJdZAgSP-4,10412 -h11/_readers.py,sha256=a4RypORUCC3d0q_kxPuBIM7jTD8iLt5X91TH0FsduN4,8590 -h11/_receivebuffer.py,sha256=xrspsdsNgWFxRfQcTXxR8RrdjRXXTK0Io5cQYWpJ1Ws,5252 -h11/_state.py,sha256=_5LG_BGR8FCcFQeBPH-TMHgm_-B-EUcWCnQof_9XjFE,13231 -h11/_util.py,sha256=LWkkjXyJaFlAy6Lt39w73UStklFT5ovcvo0TkY7RYuk,4888 -h11/_version.py,sha256=GVSsbPSPDcOuF6ptfIiXnVJoaEm3ygXbMnqlr_Giahw,686 -h11/_writers.py,sha256=oFKm6PtjeHfbj4RLX7VB7KDc1gIY53gXG3_HR9ltmTA,5081 -h11/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 diff --git a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/WHEEL b/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/WHEEL deleted file mode 100644 index 1eb3c49d99559863120cfb8433fc8738fba43ba9..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (78.1.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt b/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt deleted file mode 100644 index 8f080eae848f759c9173bfc0c79506357ebe5090..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Nathaniel J. Smith and other contributors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/top_level.txt b/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/top_level.txt deleted file mode 100644 index 0d24def711344ec6f4da2108f7d5c9261eb35f8b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11-0.16.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -h11 diff --git a/venv/lib/python3.10/site-packages/h11/__init__.py b/venv/lib/python3.10/site-packages/h11/__init__.py deleted file mode 100644 index 989e92c3458681a6f0be72ae4105ea742750d328..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -# A highish-level implementation of the HTTP/1.1 wire protocol (RFC 7230), -# containing no networking code at all, loosely modelled on hyper-h2's generic -# implementation of HTTP/2 (and in particular the h2.connection.H2Connection -# class). There's still a bunch of subtle details you need to get right if you -# want to make this actually useful, because it doesn't implement all the -# semantics to check that what you're asking to write to the wire is sensible, -# but at least it gets you out of dealing with the wire itself. - -from h11._connection import Connection, NEED_DATA, PAUSED -from h11._events import ( - ConnectionClosed, - Data, - EndOfMessage, - Event, - InformationalResponse, - Request, - Response, -) -from h11._state import ( - CLIENT, - CLOSED, - DONE, - ERROR, - IDLE, - MIGHT_SWITCH_PROTOCOL, - MUST_CLOSE, - SEND_BODY, - SEND_RESPONSE, - SERVER, - SWITCHED_PROTOCOL, -) -from h11._util import LocalProtocolError, ProtocolError, RemoteProtocolError -from h11._version import __version__ - -PRODUCT_ID = "python-h11/" + __version__ - - -__all__ = ( - "Connection", - "NEED_DATA", - "PAUSED", - "ConnectionClosed", - "Data", - "EndOfMessage", - "Event", - "InformationalResponse", - "Request", - "Response", - "CLIENT", - "CLOSED", - "DONE", - "ERROR", - "IDLE", - "MUST_CLOSE", - "SEND_BODY", - "SEND_RESPONSE", - "SERVER", - "SWITCHED_PROTOCOL", - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", -) diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index e3ab9c2bccbc1247c361432a859316e7577396bc..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_abnf.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_abnf.cpython-310.pyc deleted file mode 100644 index 2e15d620020bc5b474403e9802fb08890c55685c..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_abnf.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_connection.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_connection.cpython-310.pyc deleted file mode 100644 index 9d73e6c6a3f520ea136e8c1b405c4f389cd31f04..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_connection.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_events.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_events.cpython-310.pyc deleted file mode 100644 index e39f48ecd1ed135e5742f3147dbcd0d04b0c4c8a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_events.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_headers.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_headers.cpython-310.pyc deleted file mode 100644 index 54c6ed7e01f4314bf67915b42db0ca7e01fbc3ec..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_headers.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_readers.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_readers.cpython-310.pyc deleted file mode 100644 index 54584e6ccbba1088dd9c4d4316d7f246c61fc5d7..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_readers.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_receivebuffer.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_receivebuffer.cpython-310.pyc deleted file mode 100644 index 9288526f727b4efaa9699041fda1eaaa1b4a3d7f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_receivebuffer.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_state.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_state.cpython-310.pyc deleted file mode 100644 index e6669261aa28dc73afecfe3281b578808d6fa050..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_state.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_util.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_util.cpython-310.pyc deleted file mode 100644 index f7c5e7b5452a03ae8d7a2cc6a149976e6185e785..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_util.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_version.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_version.cpython-310.pyc deleted file mode 100644 index efbed5a68086c66a2b79f4e08820800ce0938a94..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_version.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/__pycache__/_writers.cpython-310.pyc b/venv/lib/python3.10/site-packages/h11/__pycache__/_writers.cpython-310.pyc deleted file mode 100644 index d885cac2042298b0dd25066e8057292f910c0a71..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/h11/__pycache__/_writers.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/h11/_abnf.py b/venv/lib/python3.10/site-packages/h11/_abnf.py deleted file mode 100644 index 933587fba22290d7eb7df4c88e12f1e61702b8ce..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_abnf.py +++ /dev/null @@ -1,132 +0,0 @@ -# We use native strings for all the re patterns, to take advantage of string -# formatting, and then convert to bytestrings when compiling the final re -# objects. - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#whitespace -# OWS = *( SP / HTAB ) -# ; optional whitespace -OWS = r"[ \t]*" - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.token.separators -# token = 1*tchar -# -# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" -# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" -# / DIGIT / ALPHA -# ; any VCHAR, except delimiters -token = r"[-!#$%&'*+.^_`|~0-9a-zA-Z]+" - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#header.fields -# field-name = token -field_name = token - -# The standard says: -# -# field-value = *( field-content / obs-fold ) -# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] -# field-vchar = VCHAR / obs-text -# obs-fold = CRLF 1*( SP / HTAB ) -# ; obsolete line folding -# ; see Section 3.2.4 -# -# https://tools.ietf.org/html/rfc5234#appendix-B.1 -# -# VCHAR = %x21-7E -# ; visible (printing) characters -# -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.quoted-string -# obs-text = %x80-FF -# -# However, the standard definition of field-content is WRONG! It disallows -# fields containing a single visible character surrounded by whitespace, -# e.g. "foo a bar". -# -# See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 -# -# So our definition of field_content attempts to fix it up... -# -# Also, we allow lots of control characters, because apparently people assume -# that they're legal in practice (e.g., google analytics makes cookies with -# \x01 in them!): -# https://github.com/python-hyper/h11/issues/57 -# We still don't allow NUL or whitespace, because those are often treated as -# meta-characters and letting them through can lead to nasty issues like SSRF. -vchar = r"[\x21-\x7e]" -vchar_or_obs_text = r"[^\x00\s]" -field_vchar = vchar_or_obs_text -field_content = r"{field_vchar}+(?:[ \t]+{field_vchar}+)*".format(**globals()) - -# We handle obs-fold at a different level, and our fixed-up field_content -# already grows to swallow the whole value, so ? instead of * -field_value = r"({field_content})?".format(**globals()) - -# header-field = field-name ":" OWS field-value OWS -header_field = ( - r"(?P{field_name})" - r":" - r"{OWS}" - r"(?P{field_value})" - r"{OWS}".format(**globals()) -) - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#request.line -# -# request-line = method SP request-target SP HTTP-version CRLF -# method = token -# HTTP-version = HTTP-name "/" DIGIT "." DIGIT -# HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive -# -# request-target is complicated (see RFC 7230 sec 5.3) -- could be path, full -# URL, host+port (for connect), or even "*", but in any case we are guaranteed -# that it contists of the visible printing characters. -method = token -request_target = r"{vchar}+".format(**globals()) -http_version = r"HTTP/(?P[0-9]\.[0-9])" -request_line = ( - r"(?P{method})" - r" " - r"(?P{request_target})" - r" " - r"{http_version}".format(**globals()) -) - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#status.line -# -# status-line = HTTP-version SP status-code SP reason-phrase CRLF -# status-code = 3DIGIT -# reason-phrase = *( HTAB / SP / VCHAR / obs-text ) -status_code = r"[0-9]{3}" -reason_phrase = r"([ \t]|{vchar_or_obs_text})*".format(**globals()) -status_line = ( - r"{http_version}" - r" " - r"(?P{status_code})" - # However, there are apparently a few too many servers out there that just - # leave out the reason phrase: - # https://github.com/scrapy/scrapy/issues/345#issuecomment-281756036 - # https://github.com/seanmonstar/httparse/issues/29 - # so make it optional. ?: is a non-capturing group. - r"(?: (?P{reason_phrase}))?".format(**globals()) -) - -HEXDIG = r"[0-9A-Fa-f]" -# Actually -# -# chunk-size = 1*HEXDIG -# -# but we impose an upper-limit to avoid ridiculosity. len(str(2**64)) == 20 -chunk_size = r"({HEXDIG}){{1,20}}".format(**globals()) -# Actually -# -# chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) -# -# but we aren't parsing the things so we don't really care. -chunk_ext = r";.*" -chunk_header = ( - r"(?P{chunk_size})" - r"(?P{chunk_ext})?" - r"{OWS}\r\n".format( - **globals() - ) # Even though the specification does not allow for extra whitespaces, - # we are lenient with trailing whitespaces because some servers on the wild use it. -) diff --git a/venv/lib/python3.10/site-packages/h11/_connection.py b/venv/lib/python3.10/site-packages/h11/_connection.py deleted file mode 100644 index e37d82a82a882c072cb938a90eb4486b51cdad99..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_connection.py +++ /dev/null @@ -1,659 +0,0 @@ -# This contains the main Connection class. Everything in h11 revolves around -# this. -from typing import ( - Any, - Callable, - cast, - Dict, - List, - Optional, - overload, - Tuple, - Type, - Union, -) - -from ._events import ( - ConnectionClosed, - Data, - EndOfMessage, - Event, - InformationalResponse, - Request, - Response, -) -from ._headers import get_comma_header, has_expect_100_continue, set_comma_header -from ._readers import READERS, ReadersType -from ._receivebuffer import ReceiveBuffer -from ._state import ( - _SWITCH_CONNECT, - _SWITCH_UPGRADE, - CLIENT, - ConnectionState, - DONE, - ERROR, - MIGHT_SWITCH_PROTOCOL, - SEND_BODY, - SERVER, - SWITCHED_PROTOCOL, -) -from ._util import ( # Import the internal things we need - LocalProtocolError, - RemoteProtocolError, - Sentinel, -) -from ._writers import WRITERS, WritersType - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = ["Connection", "NEED_DATA", "PAUSED"] - - -class NEED_DATA(Sentinel, metaclass=Sentinel): - pass - - -class PAUSED(Sentinel, metaclass=Sentinel): - pass - - -# If we ever have this much buffered without it making a complete parseable -# event, we error out. The only time we really buffer is when reading the -# request/response line + headers together, so this is effectively the limit on -# the size of that. -# -# Some precedents for defaults: -# - node.js: 80 * 1024 -# - tomcat: 8 * 1024 -# - IIS: 16 * 1024 -# - Apache: <8 KiB per line> -DEFAULT_MAX_INCOMPLETE_EVENT_SIZE = 16 * 1024 - - -# RFC 7230's rules for connection lifecycles: -# - If either side says they want to close the connection, then the connection -# must close. -# - HTTP/1.1 defaults to keep-alive unless someone says Connection: close -# - HTTP/1.0 defaults to close unless both sides say Connection: keep-alive -# (and even this is a mess -- e.g. if you're implementing a proxy then -# sending Connection: keep-alive is forbidden). -# -# We simplify life by simply not supporting keep-alive with HTTP/1.0 peers. So -# our rule is: -# - If someone says Connection: close, we will close -# - If someone uses HTTP/1.0, we will close. -def _keep_alive(event: Union[Request, Response]) -> bool: - connection = get_comma_header(event.headers, b"connection") - if b"close" in connection: - return False - if getattr(event, "http_version", b"1.1") < b"1.1": - return False - return True - - -def _body_framing( - request_method: bytes, event: Union[Request, Response] -) -> Tuple[str, Union[Tuple[()], Tuple[int]]]: - # Called when we enter SEND_BODY to figure out framing information for - # this body. - # - # These are the only two events that can trigger a SEND_BODY state: - assert type(event) in (Request, Response) - # Returns one of: - # - # ("content-length", count) - # ("chunked", ()) - # ("http/1.0", ()) - # - # which are (lookup key, *args) for constructing body reader/writer - # objects. - # - # Reference: https://tools.ietf.org/html/rfc7230#section-3.3.3 - # - # Step 1: some responses always have an empty body, regardless of what the - # headers say. - if type(event) is Response: - if ( - event.status_code in (204, 304) - or request_method == b"HEAD" - or (request_method == b"CONNECT" and 200 <= event.status_code < 300) - ): - return ("content-length", (0,)) - # Section 3.3.3 also lists another case -- responses with status_code - # < 200. For us these are InformationalResponses, not Responses, so - # they can't get into this function in the first place. - assert event.status_code >= 200 - - # Step 2: check for Transfer-Encoding (T-E beats C-L): - transfer_encodings = get_comma_header(event.headers, b"transfer-encoding") - if transfer_encodings: - assert transfer_encodings == [b"chunked"] - return ("chunked", ()) - - # Step 3: check for Content-Length - content_lengths = get_comma_header(event.headers, b"content-length") - if content_lengths: - return ("content-length", (int(content_lengths[0]),)) - - # Step 4: no applicable headers; fallback/default depends on type - if type(event) is Request: - return ("content-length", (0,)) - else: - return ("http/1.0", ()) - - -################################################################ -# -# The main Connection class -# -################################################################ - - -class Connection: - """An object encapsulating the state of an HTTP connection. - - Args: - our_role: If you're implementing a client, pass :data:`h11.CLIENT`. If - you're implementing a server, pass :data:`h11.SERVER`. - - max_incomplete_event_size (int): - The maximum number of bytes we're willing to buffer of an - incomplete event. In practice this mostly sets a limit on the - maximum size of the request/response line + headers. If this is - exceeded, then :meth:`next_event` will raise - :exc:`RemoteProtocolError`. - - """ - - def __init__( - self, - our_role: Type[Sentinel], - max_incomplete_event_size: int = DEFAULT_MAX_INCOMPLETE_EVENT_SIZE, - ) -> None: - self._max_incomplete_event_size = max_incomplete_event_size - # State and role tracking - if our_role not in (CLIENT, SERVER): - raise ValueError(f"expected CLIENT or SERVER, not {our_role!r}") - self.our_role = our_role - self.their_role: Type[Sentinel] - if our_role is CLIENT: - self.their_role = SERVER - else: - self.their_role = CLIENT - self._cstate = ConnectionState() - - # Callables for converting data->events or vice-versa given the - # current state - self._writer = self._get_io_object(self.our_role, None, WRITERS) - self._reader = self._get_io_object(self.their_role, None, READERS) - - # Holds any unprocessed received data - self._receive_buffer = ReceiveBuffer() - # If this is true, then it indicates that the incoming connection was - # closed *after* the end of whatever's in self._receive_buffer: - self._receive_buffer_closed = False - - # Extra bits of state that don't fit into the state machine. - # - # These two are only used to interpret framing headers for figuring - # out how to read/write response bodies. their_http_version is also - # made available as a convenient public API. - self.their_http_version: Optional[bytes] = None - self._request_method: Optional[bytes] = None - # This is pure flow-control and doesn't at all affect the set of legal - # transitions, so no need to bother ConnectionState with it: - self.client_is_waiting_for_100_continue = False - - @property - def states(self) -> Dict[Type[Sentinel], Type[Sentinel]]: - """A dictionary like:: - - {CLIENT: , SERVER: } - - See :ref:`state-machine` for details. - - """ - return dict(self._cstate.states) - - @property - def our_state(self) -> Type[Sentinel]: - """The current state of whichever role we are playing. See - :ref:`state-machine` for details. - """ - return self._cstate.states[self.our_role] - - @property - def their_state(self) -> Type[Sentinel]: - """The current state of whichever role we are NOT playing. See - :ref:`state-machine` for details. - """ - return self._cstate.states[self.their_role] - - @property - def they_are_waiting_for_100_continue(self) -> bool: - return self.their_role is CLIENT and self.client_is_waiting_for_100_continue - - def start_next_cycle(self) -> None: - """Attempt to reset our connection state for a new request/response - cycle. - - If both client and server are in :data:`DONE` state, then resets them - both to :data:`IDLE` state in preparation for a new request/response - cycle on this same connection. Otherwise, raises a - :exc:`LocalProtocolError`. - - See :ref:`keepalive-and-pipelining`. - - """ - old_states = dict(self._cstate.states) - self._cstate.start_next_cycle() - self._request_method = None - # self.their_http_version gets left alone, since it presumably lasts - # beyond a single request/response cycle - assert not self.client_is_waiting_for_100_continue - self._respond_to_state_changes(old_states) - - def _process_error(self, role: Type[Sentinel]) -> None: - old_states = dict(self._cstate.states) - self._cstate.process_error(role) - self._respond_to_state_changes(old_states) - - def _server_switch_event(self, event: Event) -> Optional[Type[Sentinel]]: - if type(event) is InformationalResponse and event.status_code == 101: - return _SWITCH_UPGRADE - if type(event) is Response: - if ( - _SWITCH_CONNECT in self._cstate.pending_switch_proposals - and 200 <= event.status_code < 300 - ): - return _SWITCH_CONNECT - return None - - # All events go through here - def _process_event(self, role: Type[Sentinel], event: Event) -> None: - # First, pass the event through the state machine to make sure it - # succeeds. - old_states = dict(self._cstate.states) - if role is CLIENT and type(event) is Request: - if event.method == b"CONNECT": - self._cstate.process_client_switch_proposal(_SWITCH_CONNECT) - if get_comma_header(event.headers, b"upgrade"): - self._cstate.process_client_switch_proposal(_SWITCH_UPGRADE) - server_switch_event = None - if role is SERVER: - server_switch_event = self._server_switch_event(event) - self._cstate.process_event(role, type(event), server_switch_event) - - # Then perform the updates triggered by it. - - if type(event) is Request: - self._request_method = event.method - - if role is self.their_role and type(event) in ( - Request, - Response, - InformationalResponse, - ): - event = cast(Union[Request, Response, InformationalResponse], event) - self.their_http_version = event.http_version - - # Keep alive handling - # - # RFC 7230 doesn't really say what one should do if Connection: close - # shows up on a 1xx InformationalResponse. I think the idea is that - # this is not supposed to happen. In any case, if it does happen, we - # ignore it. - if type(event) in (Request, Response) and not _keep_alive( - cast(Union[Request, Response], event) - ): - self._cstate.process_keep_alive_disabled() - - # 100-continue - if type(event) is Request and has_expect_100_continue(event): - self.client_is_waiting_for_100_continue = True - if type(event) in (InformationalResponse, Response): - self.client_is_waiting_for_100_continue = False - if role is CLIENT and type(event) in (Data, EndOfMessage): - self.client_is_waiting_for_100_continue = False - - self._respond_to_state_changes(old_states, event) - - def _get_io_object( - self, - role: Type[Sentinel], - event: Optional[Event], - io_dict: Union[ReadersType, WritersType], - ) -> Optional[Callable[..., Any]]: - # event may be None; it's only used when entering SEND_BODY - state = self._cstate.states[role] - if state is SEND_BODY: - # Special case: the io_dict has a dict of reader/writer factories - # that depend on the request/response framing. - framing_type, args = _body_framing( - cast(bytes, self._request_method), cast(Union[Request, Response], event) - ) - return io_dict[SEND_BODY][framing_type](*args) # type: ignore[index] - else: - # General case: the io_dict just has the appropriate reader/writer - # for this state - return io_dict.get((role, state)) # type: ignore[return-value] - - # This must be called after any action that might have caused - # self._cstate.states to change. - def _respond_to_state_changes( - self, - old_states: Dict[Type[Sentinel], Type[Sentinel]], - event: Optional[Event] = None, - ) -> None: - # Update reader/writer - if self.our_state != old_states[self.our_role]: - self._writer = self._get_io_object(self.our_role, event, WRITERS) - if self.their_state != old_states[self.their_role]: - self._reader = self._get_io_object(self.their_role, event, READERS) - - @property - def trailing_data(self) -> Tuple[bytes, bool]: - """Data that has been received, but not yet processed, represented as - a tuple with two elements, where the first is a byte-string containing - the unprocessed data itself, and the second is a bool that is True if - the receive connection was closed. - - See :ref:`switching-protocols` for discussion of why you'd want this. - """ - return (bytes(self._receive_buffer), self._receive_buffer_closed) - - def receive_data(self, data: bytes) -> None: - """Add data to our internal receive buffer. - - This does not actually do any processing on the data, just stores - it. To trigger processing, you have to call :meth:`next_event`. - - Args: - data (:term:`bytes-like object`): - The new data that was just received. - - Special case: If *data* is an empty byte-string like ``b""``, - then this indicates that the remote side has closed the - connection (end of file). Normally this is convenient, because - standard Python APIs like :meth:`file.read` or - :meth:`socket.recv` use ``b""`` to indicate end-of-file, while - other failures to read are indicated using other mechanisms - like raising :exc:`TimeoutError`. When using such an API you - can just blindly pass through whatever you get from ``read`` - to :meth:`receive_data`, and everything will work. - - But, if you have an API where reading an empty string is a - valid non-EOF condition, then you need to be aware of this and - make sure to check for such strings and avoid passing them to - :meth:`receive_data`. - - Returns: - Nothing, but after calling this you should call :meth:`next_event` - to parse the newly received data. - - Raises: - RuntimeError: - Raised if you pass an empty *data*, indicating EOF, and then - pass a non-empty *data*, indicating more data that somehow - arrived after the EOF. - - (Calling ``receive_data(b"")`` multiple times is fine, - and equivalent to calling it once.) - - """ - if data: - if self._receive_buffer_closed: - raise RuntimeError("received close, then received more data?") - self._receive_buffer += data - else: - self._receive_buffer_closed = True - - def _extract_next_receive_event( - self, - ) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: - state = self.their_state - # We don't pause immediately when they enter DONE, because even in - # DONE state we can still process a ConnectionClosed() event. But - # if we have data in our buffer, then we definitely aren't getting - # a ConnectionClosed() immediately and we need to pause. - if state is DONE and self._receive_buffer: - return PAUSED - if state is MIGHT_SWITCH_PROTOCOL or state is SWITCHED_PROTOCOL: - return PAUSED - assert self._reader is not None - event = self._reader(self._receive_buffer) - if event is None: - if not self._receive_buffer and self._receive_buffer_closed: - # In some unusual cases (basically just HTTP/1.0 bodies), EOF - # triggers an actual protocol event; in that case, we want to - # return that event, and then the state will change and we'll - # get called again to generate the actual ConnectionClosed(). - if hasattr(self._reader, "read_eof"): - event = self._reader.read_eof() - else: - event = ConnectionClosed() - if event is None: - event = NEED_DATA - return event # type: ignore[no-any-return] - - def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: - """Parse the next event out of our receive buffer, update our internal - state, and return it. - - This is a mutating operation -- think of it like calling :func:`next` - on an iterator. - - Returns: - : One of three things: - - 1) An event object -- see :ref:`events`. - - 2) The special constant :data:`NEED_DATA`, which indicates that - you need to read more data from your socket and pass it to - :meth:`receive_data` before this method will be able to return - any more events. - - 3) The special constant :data:`PAUSED`, which indicates that we - are not in a state where we can process incoming data (usually - because the peer has finished their part of the current - request/response cycle, and you have not yet called - :meth:`start_next_cycle`). See :ref:`flow-control` for details. - - Raises: - RemoteProtocolError: - The peer has misbehaved. You should close the connection - (possibly after sending some kind of 4xx response). - - Once this method returns :class:`ConnectionClosed` once, then all - subsequent calls will also return :class:`ConnectionClosed`. - - If this method raises any exception besides :exc:`RemoteProtocolError` - then that's a bug -- if it happens please file a bug report! - - If this method raises any exception then it also sets - :attr:`Connection.their_state` to :data:`ERROR` -- see - :ref:`error-handling` for discussion. - - """ - - if self.their_state is ERROR: - raise RemoteProtocolError("Can't receive data when peer state is ERROR") - try: - event = self._extract_next_receive_event() - if event not in [NEED_DATA, PAUSED]: - self._process_event(self.their_role, cast(Event, event)) - if event is NEED_DATA: - if len(self._receive_buffer) > self._max_incomplete_event_size: - # 431 is "Request header fields too large" which is pretty - # much the only situation where we can get here - raise RemoteProtocolError( - "Receive buffer too long", error_status_hint=431 - ) - if self._receive_buffer_closed: - # We're still trying to complete some event, but that's - # never going to happen because no more data is coming - raise RemoteProtocolError("peer unexpectedly closed connection") - return event - except BaseException as exc: - self._process_error(self.their_role) - if isinstance(exc, LocalProtocolError): - exc._reraise_as_remote_protocol_error() - else: - raise - - @overload - def send(self, event: ConnectionClosed) -> None: - ... - - @overload - def send( - self, event: Union[Request, InformationalResponse, Response, Data, EndOfMessage] - ) -> bytes: - ... - - @overload - def send(self, event: Event) -> Optional[bytes]: - ... - - def send(self, event: Event) -> Optional[bytes]: - """Convert a high-level event into bytes that can be sent to the peer, - while updating our internal state machine. - - Args: - event: The :ref:`event ` to send. - - Returns: - If ``type(event) is ConnectionClosed``, then returns - ``None``. Otherwise, returns a :term:`bytes-like object`. - - Raises: - LocalProtocolError: - Sending this event at this time would violate our - understanding of the HTTP/1.1 protocol. - - If this method raises any exception then it also sets - :attr:`Connection.our_state` to :data:`ERROR` -- see - :ref:`error-handling` for discussion. - - """ - data_list = self.send_with_data_passthrough(event) - if data_list is None: - return None - else: - return b"".join(data_list) - - def send_with_data_passthrough(self, event: Event) -> Optional[List[bytes]]: - """Identical to :meth:`send`, except that in situations where - :meth:`send` returns a single :term:`bytes-like object`, this instead - returns a list of them -- and when sending a :class:`Data` event, this - list is guaranteed to contain the exact object you passed in as - :attr:`Data.data`. See :ref:`sendfile` for discussion. - - """ - if self.our_state is ERROR: - raise LocalProtocolError("Can't send data when our state is ERROR") - try: - if type(event) is Response: - event = self._clean_up_response_headers_for_sending(event) - # We want to call _process_event before calling the writer, - # because if someone tries to do something invalid then this will - # give a sensible error message, while our writers all just assume - # they will only receive valid events. But, _process_event might - # change self._writer. So we have to do a little dance: - writer = self._writer - self._process_event(self.our_role, event) - if type(event) is ConnectionClosed: - return None - else: - # In any situation where writer is None, process_event should - # have raised ProtocolError - assert writer is not None - data_list: List[bytes] = [] - writer(event, data_list.append) - return data_list - except: - self._process_error(self.our_role) - raise - - def send_failed(self) -> None: - """Notify the state machine that we failed to send the data it gave - us. - - This causes :attr:`Connection.our_state` to immediately become - :data:`ERROR` -- see :ref:`error-handling` for discussion. - - """ - self._process_error(self.our_role) - - # When sending a Response, we take responsibility for a few things: - # - # - Sometimes you MUST set Connection: close. We take care of those - # times. (You can also set it yourself if you want, and if you do then - # we'll respect that and close the connection at the right time. But you - # don't have to worry about that unless you want to.) - # - # - The user has to set Content-Length if they want it. Otherwise, for - # responses that have bodies (e.g. not HEAD), then we will automatically - # select the right mechanism for streaming a body of unknown length, - # which depends on depending on the peer's HTTP version. - # - # This function's *only* responsibility is making sure headers are set up - # right -- everything downstream just looks at the headers. There are no - # side channels. - def _clean_up_response_headers_for_sending(self, response: Response) -> Response: - assert type(response) is Response - - headers = response.headers - need_close = False - - # HEAD requests need some special handling: they always act like they - # have Content-Length: 0, and that's how _body_framing treats - # them. But their headers are supposed to match what we would send if - # the request was a GET. (Technically there is one deviation allowed: - # we're allowed to leave out the framing headers -- see - # https://tools.ietf.org/html/rfc7231#section-4.3.2 . But it's just as - # easy to get them right.) - method_for_choosing_headers = cast(bytes, self._request_method) - if method_for_choosing_headers == b"HEAD": - method_for_choosing_headers = b"GET" - framing_type, _ = _body_framing(method_for_choosing_headers, response) - if framing_type in ("chunked", "http/1.0"): - # This response has a body of unknown length. - # If our peer is HTTP/1.1, we use Transfer-Encoding: chunked - # If our peer is HTTP/1.0, we use no framing headers, and close the - # connection afterwards. - # - # Make sure to clear Content-Length (in principle user could have - # set both and then we ignored Content-Length b/c - # Transfer-Encoding overwrote it -- this would be naughty of them, - # but the HTTP spec says that if our peer does this then we have - # to fix it instead of erroring out, so we'll accord the user the - # same respect). - headers = set_comma_header(headers, b"content-length", []) - if self.their_http_version is None or self.their_http_version < b"1.1": - # Either we never got a valid request and are sending back an - # error (their_http_version is None), so we assume the worst; - # or else we did get a valid HTTP/1.0 request, so we know that - # they don't understand chunked encoding. - headers = set_comma_header(headers, b"transfer-encoding", []) - # This is actually redundant ATM, since currently we - # unconditionally disable keep-alive when talking to HTTP/1.0 - # peers. But let's be defensive just in case we add - # Connection: keep-alive support later: - if self._request_method != b"HEAD": - need_close = True - else: - headers = set_comma_header(headers, b"transfer-encoding", [b"chunked"]) - - if not self._cstate.keep_alive or need_close: - # Make sure Connection: close is set - connection = set(get_comma_header(headers, b"connection")) - connection.discard(b"keep-alive") - connection.add(b"close") - headers = set_comma_header(headers, b"connection", sorted(connection)) - - return Response( - headers=headers, - status_code=response.status_code, - http_version=response.http_version, - reason=response.reason, - ) diff --git a/venv/lib/python3.10/site-packages/h11/_events.py b/venv/lib/python3.10/site-packages/h11/_events.py deleted file mode 100644 index ca1c3adbde2c4e7710482a18e3471f91f1da610e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_events.py +++ /dev/null @@ -1,369 +0,0 @@ -# High level events that make up HTTP/1.1 conversations. Loosely inspired by -# the corresponding events in hyper-h2: -# -# http://python-hyper.org/h2/en/stable/api.html#events -# -# Don't subclass these. Stuff will break. - -import re -from abc import ABC -from dataclasses import dataclass -from typing import List, Tuple, Union - -from ._abnf import method, request_target -from ._headers import Headers, normalize_and_validate -from ._util import bytesify, LocalProtocolError, validate - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = [ - "Event", - "Request", - "InformationalResponse", - "Response", - "Data", - "EndOfMessage", - "ConnectionClosed", -] - -method_re = re.compile(method.encode("ascii")) -request_target_re = re.compile(request_target.encode("ascii")) - - -class Event(ABC): - """ - Base class for h11 events. - """ - - __slots__ = () - - -@dataclass(init=False, frozen=True) -class Request(Event): - """The beginning of an HTTP request. - - Fields: - - .. attribute:: method - - An HTTP method, e.g. ``b"GET"`` or ``b"POST"``. Always a byte - string. :term:`Bytes-like objects ` and native - strings containing only ascii characters will be automatically - converted to byte strings. - - .. attribute:: target - - The target of an HTTP request, e.g. ``b"/index.html"``, or one of the - more exotic formats described in `RFC 7320, section 5.3 - `_. Always a byte - string. :term:`Bytes-like objects ` and native - strings containing only ascii characters will be automatically - converted to byte strings. - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - """ - - __slots__ = ("method", "headers", "target", "http_version") - - method: bytes - headers: Headers - target: bytes - http_version: bytes - - def __init__( - self, - *, - method: Union[bytes, str], - headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], - target: Union[bytes, str], - http_version: Union[bytes, str] = b"1.1", - _parsed: bool = False, - ) -> None: - super().__init__() - if isinstance(headers, Headers): - object.__setattr__(self, "headers", headers) - else: - object.__setattr__( - self, "headers", normalize_and_validate(headers, _parsed=_parsed) - ) - if not _parsed: - object.__setattr__(self, "method", bytesify(method)) - object.__setattr__(self, "target", bytesify(target)) - object.__setattr__(self, "http_version", bytesify(http_version)) - else: - object.__setattr__(self, "method", method) - object.__setattr__(self, "target", target) - object.__setattr__(self, "http_version", http_version) - - # "A server MUST respond with a 400 (Bad Request) status code to any - # HTTP/1.1 request message that lacks a Host header field and to any - # request message that contains more than one Host header field or a - # Host header field with an invalid field-value." - # -- https://tools.ietf.org/html/rfc7230#section-5.4 - host_count = 0 - for name, value in self.headers: - if name == b"host": - host_count += 1 - if self.http_version == b"1.1" and host_count == 0: - raise LocalProtocolError("Missing mandatory Host: header") - if host_count > 1: - raise LocalProtocolError("Found multiple Host: headers") - - validate(method_re, self.method, "Illegal method characters") - validate(request_target_re, self.target, "Illegal target characters") - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class _ResponseBase(Event): - __slots__ = ("headers", "http_version", "reason", "status_code") - - headers: Headers - http_version: bytes - reason: bytes - status_code: int - - def __init__( - self, - *, - headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], - status_code: int, - http_version: Union[bytes, str] = b"1.1", - reason: Union[bytes, str] = b"", - _parsed: bool = False, - ) -> None: - super().__init__() - if isinstance(headers, Headers): - object.__setattr__(self, "headers", headers) - else: - object.__setattr__( - self, "headers", normalize_and_validate(headers, _parsed=_parsed) - ) - if not _parsed: - object.__setattr__(self, "reason", bytesify(reason)) - object.__setattr__(self, "http_version", bytesify(http_version)) - if not isinstance(status_code, int): - raise LocalProtocolError("status code must be integer") - # Because IntEnum objects are instances of int, but aren't - # duck-compatible (sigh), see gh-72. - object.__setattr__(self, "status_code", int(status_code)) - else: - object.__setattr__(self, "reason", reason) - object.__setattr__(self, "http_version", http_version) - object.__setattr__(self, "status_code", status_code) - - self.__post_init__() - - def __post_init__(self) -> None: - pass - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class InformationalResponse(_ResponseBase): - """An HTTP informational response. - - Fields: - - .. attribute:: status_code - - The status code of this response, as an integer. For an - :class:`InformationalResponse`, this is always in the range [100, - 200). - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for - details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - .. attribute:: reason - - The reason phrase of this response, as a byte string. For example: - ``b"OK"``, or ``b"Not Found"``. - - """ - - def __post_init__(self) -> None: - if not (100 <= self.status_code < 200): - raise LocalProtocolError( - "InformationalResponse status_code should be in range " - "[100, 200), not {}".format(self.status_code) - ) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class Response(_ResponseBase): - """The beginning of an HTTP response. - - Fields: - - .. attribute:: status_code - - The status code of this response, as an integer. For an - :class:`Response`, this is always in the range [200, - 1000). - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - .. attribute:: reason - - The reason phrase of this response, as a byte string. For example: - ``b"OK"``, or ``b"Not Found"``. - - """ - - def __post_init__(self) -> None: - if not (200 <= self.status_code < 1000): - raise LocalProtocolError( - "Response status_code should be in range [200, 1000), not {}".format( - self.status_code - ) - ) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class Data(Event): - """Part of an HTTP message body. - - Fields: - - .. attribute:: data - - A :term:`bytes-like object` containing part of a message body. Or, if - using the ``combine=False`` argument to :meth:`Connection.send`, then - any object that your socket writing code knows what to do with, and for - which calling :func:`len` returns the number of bytes that will be - written -- see :ref:`sendfile` for details. - - .. attribute:: chunk_start - - A marker that indicates whether this data object is from the start of a - chunked transfer encoding chunk. This field is ignored when when a Data - event is provided to :meth:`Connection.send`: it is only valid on - events emitted from :meth:`Connection.next_event`. You probably - shouldn't use this attribute at all; see - :ref:`chunk-delimiters-are-bad` for details. - - .. attribute:: chunk_end - - A marker that indicates whether this data object is the last for a - given chunked transfer encoding chunk. This field is ignored when when - a Data event is provided to :meth:`Connection.send`: it is only valid - on events emitted from :meth:`Connection.next_event`. You probably - shouldn't use this attribute at all; see - :ref:`chunk-delimiters-are-bad` for details. - - """ - - __slots__ = ("data", "chunk_start", "chunk_end") - - data: bytes - chunk_start: bool - chunk_end: bool - - def __init__( - self, data: bytes, chunk_start: bool = False, chunk_end: bool = False - ) -> None: - object.__setattr__(self, "data", data) - object.__setattr__(self, "chunk_start", chunk_start) - object.__setattr__(self, "chunk_end", chunk_end) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -# XX FIXME: "A recipient MUST ignore (or consider as an error) any fields that -# are forbidden to be sent in a trailer, since processing them as if they were -# present in the header section might bypass external security filters." -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#chunked.trailer.part -# Unfortunately, the list of forbidden fields is long and vague :-/ -@dataclass(init=False, frozen=True) -class EndOfMessage(Event): - """The end of an HTTP message. - - Fields: - - .. attribute:: headers - - Default value: ``[]`` - - Any trailing headers attached to this message, represented as a list of - (name, value) pairs. See :ref:`the header normalization rules - ` for details. - - Must be empty unless ``Transfer-Encoding: chunked`` is in use. - - """ - - __slots__ = ("headers",) - - headers: Headers - - def __init__( - self, - *, - headers: Union[ - Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]], None - ] = None, - _parsed: bool = False, - ) -> None: - super().__init__() - if headers is None: - headers = Headers([]) - elif not isinstance(headers, Headers): - headers = normalize_and_validate(headers, _parsed=_parsed) - - object.__setattr__(self, "headers", headers) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(frozen=True) -class ConnectionClosed(Event): - """This event indicates that the sender has closed their outgoing - connection. - - Note that this does not necessarily mean that they can't *receive* further - data, because TCP connections are composed to two one-way channels which - can be closed independently. See :ref:`closing` for details. - - No fields. - """ - - pass diff --git a/venv/lib/python3.10/site-packages/h11/_headers.py b/venv/lib/python3.10/site-packages/h11/_headers.py deleted file mode 100644 index 31da3e2b23b55a624b36f105e62a6902e63286aa..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_headers.py +++ /dev/null @@ -1,282 +0,0 @@ -import re -from typing import AnyStr, cast, List, overload, Sequence, Tuple, TYPE_CHECKING, Union - -from ._abnf import field_name, field_value -from ._util import bytesify, LocalProtocolError, validate - -if TYPE_CHECKING: - from ._events import Request - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal # type: ignore - -CONTENT_LENGTH_MAX_DIGITS = 20 # allow up to 1 billion TB - 1 - - -# Facts -# ----- -# -# Headers are: -# keys: case-insensitive ascii -# values: mixture of ascii and raw bytes -# -# "Historically, HTTP has allowed field content with text in the ISO-8859-1 -# charset [ISO-8859-1], supporting other charsets only through use of -# [RFC2047] encoding. In practice, most HTTP header field values use only a -# subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD -# limit their field values to US-ASCII octets. A recipient SHOULD treat other -# octets in field content (obs-text) as opaque data." -# And it deprecates all non-ascii values -# -# Leading/trailing whitespace in header names is forbidden -# -# Values get leading/trailing whitespace stripped -# -# Content-Disposition actually needs to contain unicode semantically; to -# accomplish this it has a terrifically weird way of encoding the filename -# itself as ascii (and even this still has lots of cross-browser -# incompatibilities) -# -# Order is important: -# "a proxy MUST NOT change the order of these field values when forwarding a -# message" -# (and there are several headers where the order indicates a preference) -# -# Multiple occurences of the same header: -# "A sender MUST NOT generate multiple header fields with the same field name -# in a message unless either the entire field value for that header field is -# defined as a comma-separated list [or the header is Set-Cookie which gets a -# special exception]" - RFC 7230. (cookies are in RFC 6265) -# -# So every header aside from Set-Cookie can be merged by b", ".join if it -# occurs repeatedly. But, of course, they can't necessarily be split by -# .split(b","), because quoting. -# -# Given all this mess (case insensitive, duplicates allowed, order is -# important, ...), there doesn't appear to be any standard way to handle -# headers in Python -- they're almost like dicts, but... actually just -# aren't. For now we punt and just use a super simple representation: headers -# are a list of pairs -# -# [(name1, value1), (name2, value2), ...] -# -# where all entries are bytestrings, names are lowercase and have no -# leading/trailing whitespace, and values are bytestrings with no -# leading/trailing whitespace. Searching and updating are done via naive O(n) -# methods. -# -# Maybe a dict-of-lists would be better? - -_content_length_re = re.compile(rb"[0-9]+") -_field_name_re = re.compile(field_name.encode("ascii")) -_field_value_re = re.compile(field_value.encode("ascii")) - - -class Headers(Sequence[Tuple[bytes, bytes]]): - """ - A list-like interface that allows iterating over headers as byte-pairs - of (lowercased-name, value). - - Internally we actually store the representation as three-tuples, - including both the raw original casing, in order to preserve casing - over-the-wire, and the lowercased name, for case-insensitive comparisions. - - r = Request( - method="GET", - target="/", - headers=[("Host", "example.org"), ("Connection", "keep-alive")], - http_version="1.1", - ) - assert r.headers == [ - (b"host", b"example.org"), - (b"connection", b"keep-alive") - ] - assert r.headers.raw_items() == [ - (b"Host", b"example.org"), - (b"Connection", b"keep-alive") - ] - """ - - __slots__ = "_full_items" - - def __init__(self, full_items: List[Tuple[bytes, bytes, bytes]]) -> None: - self._full_items = full_items - - def __bool__(self) -> bool: - return bool(self._full_items) - - def __eq__(self, other: object) -> bool: - return list(self) == list(other) # type: ignore - - def __len__(self) -> int: - return len(self._full_items) - - def __repr__(self) -> str: - return "" % repr(list(self)) - - def __getitem__(self, idx: int) -> Tuple[bytes, bytes]: # type: ignore[override] - _, name, value = self._full_items[idx] - return (name, value) - - def raw_items(self) -> List[Tuple[bytes, bytes]]: - return [(raw_name, value) for raw_name, _, value in self._full_items] - - -HeaderTypes = Union[ - List[Tuple[bytes, bytes]], - List[Tuple[bytes, str]], - List[Tuple[str, bytes]], - List[Tuple[str, str]], -] - - -@overload -def normalize_and_validate(headers: Headers, _parsed: Literal[True]) -> Headers: - ... - - -@overload -def normalize_and_validate(headers: HeaderTypes, _parsed: Literal[False]) -> Headers: - ... - - -@overload -def normalize_and_validate( - headers: Union[Headers, HeaderTypes], _parsed: bool = False -) -> Headers: - ... - - -def normalize_and_validate( - headers: Union[Headers, HeaderTypes], _parsed: bool = False -) -> Headers: - new_headers = [] - seen_content_length = None - saw_transfer_encoding = False - for name, value in headers: - # For headers coming out of the parser, we can safely skip some steps, - # because it always returns bytes and has already run these regexes - # over the data: - if not _parsed: - name = bytesify(name) - value = bytesify(value) - validate(_field_name_re, name, "Illegal header name {!r}", name) - validate(_field_value_re, value, "Illegal header value {!r}", value) - assert isinstance(name, bytes) - assert isinstance(value, bytes) - - raw_name = name - name = name.lower() - if name == b"content-length": - lengths = {length.strip() for length in value.split(b",")} - if len(lengths) != 1: - raise LocalProtocolError("conflicting Content-Length headers") - value = lengths.pop() - validate(_content_length_re, value, "bad Content-Length") - if len(value) > CONTENT_LENGTH_MAX_DIGITS: - raise LocalProtocolError("bad Content-Length") - if seen_content_length is None: - seen_content_length = value - new_headers.append((raw_name, name, value)) - elif seen_content_length != value: - raise LocalProtocolError("conflicting Content-Length headers") - elif name == b"transfer-encoding": - # "A server that receives a request message with a transfer coding - # it does not understand SHOULD respond with 501 (Not - # Implemented)." - # https://tools.ietf.org/html/rfc7230#section-3.3.1 - if saw_transfer_encoding: - raise LocalProtocolError( - "multiple Transfer-Encoding headers", error_status_hint=501 - ) - # "All transfer-coding names are case-insensitive" - # -- https://tools.ietf.org/html/rfc7230#section-4 - value = value.lower() - if value != b"chunked": - raise LocalProtocolError( - "Only Transfer-Encoding: chunked is supported", - error_status_hint=501, - ) - saw_transfer_encoding = True - new_headers.append((raw_name, name, value)) - else: - new_headers.append((raw_name, name, value)) - return Headers(new_headers) - - -def get_comma_header(headers: Headers, name: bytes) -> List[bytes]: - # Should only be used for headers whose value is a list of - # comma-separated, case-insensitive values. - # - # The header name `name` is expected to be lower-case bytes. - # - # Connection: meets these criteria (including cast insensitivity). - # - # Content-Length: technically is just a single value (1*DIGIT), but the - # standard makes reference to implementations that do multiple values, and - # using this doesn't hurt. Ditto, case insensitivity doesn't things either - # way. - # - # Transfer-Encoding: is more complex (allows for quoted strings), so - # splitting on , is actually wrong. For example, this is legal: - # - # Transfer-Encoding: foo; options="1,2", chunked - # - # and should be parsed as - # - # foo; options="1,2" - # chunked - # - # but this naive function will parse it as - # - # foo; options="1 - # 2" - # chunked - # - # However, this is okay because the only thing we are going to do with - # any Transfer-Encoding is reject ones that aren't just "chunked", so - # both of these will be treated the same anyway. - # - # Expect: the only legal value is the literal string - # "100-continue". Splitting on commas is harmless. Case insensitive. - # - out: List[bytes] = [] - for _, found_name, found_raw_value in headers._full_items: - if found_name == name: - found_raw_value = found_raw_value.lower() - for found_split_value in found_raw_value.split(b","): - found_split_value = found_split_value.strip() - if found_split_value: - out.append(found_split_value) - return out - - -def set_comma_header(headers: Headers, name: bytes, new_values: List[bytes]) -> Headers: - # The header name `name` is expected to be lower-case bytes. - # - # Note that when we store the header we use title casing for the header - # names, in order to match the conventional HTTP header style. - # - # Simply calling `.title()` is a blunt approach, but it's correct - # here given the cases where we're using `set_comma_header`... - # - # Connection, Content-Length, Transfer-Encoding. - new_headers: List[Tuple[bytes, bytes]] = [] - for found_raw_name, found_name, found_raw_value in headers._full_items: - if found_name != name: - new_headers.append((found_raw_name, found_raw_value)) - for new_value in new_values: - new_headers.append((name.title(), new_value)) - return normalize_and_validate(new_headers) - - -def has_expect_100_continue(request: "Request") -> bool: - # https://tools.ietf.org/html/rfc7231#section-5.1.1 - # "A server that receives a 100-continue expectation in an HTTP/1.0 request - # MUST ignore that expectation." - if request.http_version < b"1.1": - return False - expect = get_comma_header(request.headers, b"expect") - return b"100-continue" in expect diff --git a/venv/lib/python3.10/site-packages/h11/_readers.py b/venv/lib/python3.10/site-packages/h11/_readers.py deleted file mode 100644 index 576804cc282032526e0a932c9853d586a094bad0..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_readers.py +++ /dev/null @@ -1,250 +0,0 @@ -# Code to read HTTP data -# -# Strategy: each reader is a callable which takes a ReceiveBuffer object, and -# either: -# 1) consumes some of it and returns an Event -# 2) raises a LocalProtocolError (for consistency -- e.g. we call validate() -# and it might raise a LocalProtocolError, so simpler just to always use -# this) -# 3) returns None, meaning "I need more data" -# -# If they have a .read_eof attribute, then this will be called if an EOF is -# received -- but this is optional. Either way, the actual ConnectionClosed -# event will be generated afterwards. -# -# READERS is a dict describing how to pick a reader. It maps states to either: -# - a reader -# - or, for body readers, a dict of per-framing reader factories - -import re -from typing import Any, Callable, Dict, Iterable, NoReturn, Optional, Tuple, Type, Union - -from ._abnf import chunk_header, header_field, request_line, status_line -from ._events import Data, EndOfMessage, InformationalResponse, Request, Response -from ._receivebuffer import ReceiveBuffer -from ._state import ( - CLIENT, - CLOSED, - DONE, - IDLE, - MUST_CLOSE, - SEND_BODY, - SEND_RESPONSE, - SERVER, -) -from ._util import LocalProtocolError, RemoteProtocolError, Sentinel, validate - -__all__ = ["READERS"] - -header_field_re = re.compile(header_field.encode("ascii")) -obs_fold_re = re.compile(rb"[ \t]+") - - -def _obsolete_line_fold(lines: Iterable[bytes]) -> Iterable[bytes]: - it = iter(lines) - last: Optional[bytes] = None - for line in it: - match = obs_fold_re.match(line) - if match: - if last is None: - raise LocalProtocolError("continuation line at start of headers") - if not isinstance(last, bytearray): - # Cast to a mutable type, avoiding copy on append to ensure O(n) time - last = bytearray(last) - last += b" " - last += line[match.end() :] - else: - if last is not None: - yield last - last = line - if last is not None: - yield last - - -def _decode_header_lines( - lines: Iterable[bytes], -) -> Iterable[Tuple[bytes, bytes]]: - for line in _obsolete_line_fold(lines): - matches = validate(header_field_re, line, "illegal header line: {!r}", line) - yield (matches["field_name"], matches["field_value"]) - - -request_line_re = re.compile(request_line.encode("ascii")) - - -def maybe_read_from_IDLE_client(buf: ReceiveBuffer) -> Optional[Request]: - lines = buf.maybe_extract_lines() - if lines is None: - if buf.is_next_line_obviously_invalid_request_line(): - raise LocalProtocolError("illegal request line") - return None - if not lines: - raise LocalProtocolError("no request line received") - matches = validate( - request_line_re, lines[0], "illegal request line: {!r}", lines[0] - ) - return Request( - headers=list(_decode_header_lines(lines[1:])), _parsed=True, **matches - ) - - -status_line_re = re.compile(status_line.encode("ascii")) - - -def maybe_read_from_SEND_RESPONSE_server( - buf: ReceiveBuffer, -) -> Union[InformationalResponse, Response, None]: - lines = buf.maybe_extract_lines() - if lines is None: - if buf.is_next_line_obviously_invalid_request_line(): - raise LocalProtocolError("illegal request line") - return None - if not lines: - raise LocalProtocolError("no response line received") - matches = validate(status_line_re, lines[0], "illegal status line: {!r}", lines[0]) - http_version = ( - b"1.1" if matches["http_version"] is None else matches["http_version"] - ) - reason = b"" if matches["reason"] is None else matches["reason"] - status_code = int(matches["status_code"]) - class_: Union[Type[InformationalResponse], Type[Response]] = ( - InformationalResponse if status_code < 200 else Response - ) - return class_( - headers=list(_decode_header_lines(lines[1:])), - _parsed=True, - status_code=status_code, - reason=reason, - http_version=http_version, - ) - - -class ContentLengthReader: - def __init__(self, length: int) -> None: - self._length = length - self._remaining = length - - def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: - if self._remaining == 0: - return EndOfMessage() - data = buf.maybe_extract_at_most(self._remaining) - if data is None: - return None - self._remaining -= len(data) - return Data(data=data) - - def read_eof(self) -> NoReturn: - raise RemoteProtocolError( - "peer closed connection without sending complete message body " - "(received {} bytes, expected {})".format( - self._length - self._remaining, self._length - ) - ) - - -chunk_header_re = re.compile(chunk_header.encode("ascii")) - - -class ChunkedReader: - def __init__(self) -> None: - self._bytes_in_chunk = 0 - # After reading a chunk, we have to throw away the trailing \r\n. - # This tracks the bytes that we need to match and throw away. - self._bytes_to_discard = b"" - self._reading_trailer = False - - def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: - if self._reading_trailer: - lines = buf.maybe_extract_lines() - if lines is None: - return None - return EndOfMessage(headers=list(_decode_header_lines(lines))) - if self._bytes_to_discard: - data = buf.maybe_extract_at_most(len(self._bytes_to_discard)) - if data is None: - return None - if data != self._bytes_to_discard[: len(data)]: - raise LocalProtocolError( - f"malformed chunk footer: {data!r} (expected {self._bytes_to_discard!r})" - ) - self._bytes_to_discard = self._bytes_to_discard[len(data) :] - if self._bytes_to_discard: - return None - # else, fall through and read some more - assert self._bytes_to_discard == b"" - if self._bytes_in_chunk == 0: - # We need to refill our chunk count - chunk_header = buf.maybe_extract_next_line() - if chunk_header is None: - return None - matches = validate( - chunk_header_re, - chunk_header, - "illegal chunk header: {!r}", - chunk_header, - ) - # XX FIXME: we discard chunk extensions. Does anyone care? - self._bytes_in_chunk = int(matches["chunk_size"], base=16) - if self._bytes_in_chunk == 0: - self._reading_trailer = True - return self(buf) - chunk_start = True - else: - chunk_start = False - assert self._bytes_in_chunk > 0 - data = buf.maybe_extract_at_most(self._bytes_in_chunk) - if data is None: - return None - self._bytes_in_chunk -= len(data) - if self._bytes_in_chunk == 0: - self._bytes_to_discard = b"\r\n" - chunk_end = True - else: - chunk_end = False - return Data(data=data, chunk_start=chunk_start, chunk_end=chunk_end) - - def read_eof(self) -> NoReturn: - raise RemoteProtocolError( - "peer closed connection without sending complete message body " - "(incomplete chunked read)" - ) - - -class Http10Reader: - def __call__(self, buf: ReceiveBuffer) -> Optional[Data]: - data = buf.maybe_extract_at_most(999999999) - if data is None: - return None - return Data(data=data) - - def read_eof(self) -> EndOfMessage: - return EndOfMessage() - - -def expect_nothing(buf: ReceiveBuffer) -> None: - if buf: - raise LocalProtocolError("Got data when expecting EOF") - return None - - -ReadersType = Dict[ - Union[Type[Sentinel], Tuple[Type[Sentinel], Type[Sentinel]]], - Union[Callable[..., Any], Dict[str, Callable[..., Any]]], -] - -READERS: ReadersType = { - (CLIENT, IDLE): maybe_read_from_IDLE_client, - (SERVER, IDLE): maybe_read_from_SEND_RESPONSE_server, - (SERVER, SEND_RESPONSE): maybe_read_from_SEND_RESPONSE_server, - (CLIENT, DONE): expect_nothing, - (CLIENT, MUST_CLOSE): expect_nothing, - (CLIENT, CLOSED): expect_nothing, - (SERVER, DONE): expect_nothing, - (SERVER, MUST_CLOSE): expect_nothing, - (SERVER, CLOSED): expect_nothing, - SEND_BODY: { - "chunked": ChunkedReader, - "content-length": ContentLengthReader, - "http/1.0": Http10Reader, - }, -} diff --git a/venv/lib/python3.10/site-packages/h11/_receivebuffer.py b/venv/lib/python3.10/site-packages/h11/_receivebuffer.py deleted file mode 100644 index e5c4e08a56f5081e87103f38b4add6ce1b730204..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_receivebuffer.py +++ /dev/null @@ -1,153 +0,0 @@ -import re -import sys -from typing import List, Optional, Union - -__all__ = ["ReceiveBuffer"] - - -# Operations we want to support: -# - find next \r\n or \r\n\r\n (\n or \n\n are also acceptable), -# or wait until there is one -# - read at-most-N bytes -# Goals: -# - on average, do this fast -# - worst case, do this in O(n) where n is the number of bytes processed -# Plan: -# - store bytearray, offset, how far we've searched for a separator token -# - use the how-far-we've-searched data to avoid rescanning -# - while doing a stream of uninterrupted processing, advance offset instead -# of constantly copying -# WARNING: -# - I haven't benchmarked or profiled any of this yet. -# -# Note that starting in Python 3.4, deleting the initial n bytes from a -# bytearray is amortized O(n), thanks to some excellent work by Antoine -# Martin: -# -# https://bugs.python.org/issue19087 -# -# This means that if we only supported 3.4+, we could get rid of the code here -# involving self._start and self.compress, because it's doing exactly the same -# thing that bytearray now does internally. -# -# BUT unfortunately, we still support 2.7, and reading short segments out of a -# long buffer MUST be O(bytes read) to avoid DoS issues, so we can't actually -# delete this code. Yet: -# -# https://pythonclock.org/ -# -# (Two things to double-check first though: make sure PyPy also has the -# optimization, and benchmark to make sure it's a win, since we do have a -# slightly clever thing where we delay calling compress() until we've -# processed a whole event, which could in theory be slightly more efficient -# than the internal bytearray support.) -blank_line_regex = re.compile(b"\n\r?\n", re.MULTILINE) - - -class ReceiveBuffer: - def __init__(self) -> None: - self._data = bytearray() - self._next_line_search = 0 - self._multiple_lines_search = 0 - - def __iadd__(self, byteslike: Union[bytes, bytearray]) -> "ReceiveBuffer": - self._data += byteslike - return self - - def __bool__(self) -> bool: - return bool(len(self)) - - def __len__(self) -> int: - return len(self._data) - - # for @property unprocessed_data - def __bytes__(self) -> bytes: - return bytes(self._data) - - def _extract(self, count: int) -> bytearray: - # extracting an initial slice of the data buffer and return it - out = self._data[:count] - del self._data[:count] - - self._next_line_search = 0 - self._multiple_lines_search = 0 - - return out - - def maybe_extract_at_most(self, count: int) -> Optional[bytearray]: - """ - Extract a fixed number of bytes from the buffer. - """ - out = self._data[:count] - if not out: - return None - - return self._extract(count) - - def maybe_extract_next_line(self) -> Optional[bytearray]: - """ - Extract the first line, if it is completed in the buffer. - """ - # Only search in buffer space that we've not already looked at. - search_start_index = max(0, self._next_line_search - 1) - partial_idx = self._data.find(b"\r\n", search_start_index) - - if partial_idx == -1: - self._next_line_search = len(self._data) - return None - - # + 2 is to compensate len(b"\r\n") - idx = partial_idx + 2 - - return self._extract(idx) - - def maybe_extract_lines(self) -> Optional[List[bytearray]]: - """ - Extract everything up to the first blank line, and return a list of lines. - """ - # Handle the case where we have an immediate empty line. - if self._data[:1] == b"\n": - self._extract(1) - return [] - - if self._data[:2] == b"\r\n": - self._extract(2) - return [] - - # Only search in buffer space that we've not already looked at. - match = blank_line_regex.search(self._data, self._multiple_lines_search) - if match is None: - self._multiple_lines_search = max(0, len(self._data) - 2) - return None - - # Truncate the buffer and return it. - idx = match.span(0)[-1] - out = self._extract(idx) - lines = out.split(b"\n") - - for line in lines: - if line.endswith(b"\r"): - del line[-1] - - assert lines[-2] == lines[-1] == b"" - - del lines[-2:] - - return lines - - # In theory we should wait until `\r\n` before starting to validate - # incoming data. However it's interesting to detect (very) invalid data - # early given they might not even contain `\r\n` at all (hence only - # timeout will get rid of them). - # This is not a 100% effective detection but more of a cheap sanity check - # allowing for early abort in some useful cases. - # This is especially interesting when peer is messing up with HTTPS and - # sent us a TLS stream where we were expecting plain HTTP given all - # versions of TLS so far start handshake with a 0x16 message type code. - def is_next_line_obviously_invalid_request_line(self) -> bool: - try: - # HTTP header line must not contain non-printable characters - # and should not start with a space - return self._data[0] < 0x21 - except IndexError: - return False diff --git a/venv/lib/python3.10/site-packages/h11/_state.py b/venv/lib/python3.10/site-packages/h11/_state.py deleted file mode 100644 index 3ad444b043e3f3d6c05c2d9d84d5119312bfaa34..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_state.py +++ /dev/null @@ -1,365 +0,0 @@ -################################################################ -# The core state machine -################################################################ -# -# Rule 1: everything that affects the state machine and state transitions must -# live here in this file. As much as possible goes into the table-based -# representation, but for the bits that don't quite fit, the actual code and -# state must nonetheless live here. -# -# Rule 2: this file does not know about what role we're playing; it only knows -# about HTTP request/response cycles in the abstract. This ensures that we -# don't cheat and apply different rules to local and remote parties. -# -# -# Theory of operation -# =================== -# -# Possibly the simplest way to think about this is that we actually have 5 -# different state machines here. Yes, 5. These are: -# -# 1) The client state, with its complicated automaton (see the docs) -# 2) The server state, with its complicated automaton (see the docs) -# 3) The keep-alive state, with possible states {True, False} -# 4) The SWITCH_CONNECT state, with possible states {False, True} -# 5) The SWITCH_UPGRADE state, with possible states {False, True} -# -# For (3)-(5), the first state listed is the initial state. -# -# (1)-(3) are stored explicitly in member variables. The last -# two are stored implicitly in the pending_switch_proposals set as: -# (state of 4) == (_SWITCH_CONNECT in pending_switch_proposals) -# (state of 5) == (_SWITCH_UPGRADE in pending_switch_proposals) -# -# And each of these machines has two different kinds of transitions: -# -# a) Event-triggered -# b) State-triggered -# -# Event triggered is the obvious thing that you'd think it is: some event -# happens, and if it's the right event at the right time then a transition -# happens. But there are somewhat complicated rules for which machines can -# "see" which events. (As a rule of thumb, if a machine "sees" an event, this -# means two things: the event can affect the machine, and if the machine is -# not in a state where it expects that event then it's an error.) These rules -# are: -# -# 1) The client machine sees all h11.events objects emitted by the client. -# -# 2) The server machine sees all h11.events objects emitted by the server. -# -# It also sees the client's Request event. -# -# And sometimes, server events are annotated with a _SWITCH_* event. For -# example, we can have a (Response, _SWITCH_CONNECT) event, which is -# different from a regular Response event. -# -# 3) The keep-alive machine sees the process_keep_alive_disabled() event -# (which is derived from Request/Response events), and this event -# transitions it from True -> False, or from False -> False. There's no way -# to transition back. -# -# 4&5) The _SWITCH_* machines transition from False->True when we get a -# Request that proposes the relevant type of switch (via -# process_client_switch_proposals), and they go from True->False when we -# get a Response that has no _SWITCH_* annotation. -# -# So that's event-triggered transitions. -# -# State-triggered transitions are less standard. What they do here is couple -# the machines together. The way this works is, when certain *joint* -# configurations of states are achieved, then we automatically transition to a -# new *joint* state. So, for example, if we're ever in a joint state with -# -# client: DONE -# keep-alive: False -# -# then the client state immediately transitions to: -# -# client: MUST_CLOSE -# -# This is fundamentally different from an event-based transition, because it -# doesn't matter how we arrived at the {client: DONE, keep-alive: False} state -# -- maybe the client transitioned SEND_BODY -> DONE, or keep-alive -# transitioned True -> False. Either way, once this precondition is satisfied, -# this transition is immediately triggered. -# -# What if two conflicting state-based transitions get enabled at the same -# time? In practice there's only one case where this arises (client DONE -> -# MIGHT_SWITCH_PROTOCOL versus DONE -> MUST_CLOSE), and we resolve it by -# explicitly prioritizing the DONE -> MIGHT_SWITCH_PROTOCOL transition. -# -# Implementation -# -------------- -# -# The event-triggered transitions for the server and client machines are all -# stored explicitly in a table. Ditto for the state-triggered transitions that -# involve just the server and client state. -# -# The transitions for the other machines, and the state-triggered transitions -# that involve the other machines, are written out as explicit Python code. -# -# It'd be nice if there were some cleaner way to do all this. This isn't -# *too* terrible, but I feel like it could probably be better. -# -# WARNING -# ------- -# -# The script that generates the state machine diagrams for the docs knows how -# to read out the EVENT_TRIGGERED_TRANSITIONS and STATE_TRIGGERED_TRANSITIONS -# tables. But it can't automatically read the transitions that are written -# directly in Python code. So if you touch those, you need to also update the -# script to keep it in sync! -from typing import cast, Dict, Optional, Set, Tuple, Type, Union - -from ._events import * -from ._util import LocalProtocolError, Sentinel - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = [ - "CLIENT", - "SERVER", - "IDLE", - "SEND_RESPONSE", - "SEND_BODY", - "DONE", - "MUST_CLOSE", - "CLOSED", - "MIGHT_SWITCH_PROTOCOL", - "SWITCHED_PROTOCOL", - "ERROR", -] - - -class CLIENT(Sentinel, metaclass=Sentinel): - pass - - -class SERVER(Sentinel, metaclass=Sentinel): - pass - - -# States -class IDLE(Sentinel, metaclass=Sentinel): - pass - - -class SEND_RESPONSE(Sentinel, metaclass=Sentinel): - pass - - -class SEND_BODY(Sentinel, metaclass=Sentinel): - pass - - -class DONE(Sentinel, metaclass=Sentinel): - pass - - -class MUST_CLOSE(Sentinel, metaclass=Sentinel): - pass - - -class CLOSED(Sentinel, metaclass=Sentinel): - pass - - -class ERROR(Sentinel, metaclass=Sentinel): - pass - - -# Switch types -class MIGHT_SWITCH_PROTOCOL(Sentinel, metaclass=Sentinel): - pass - - -class SWITCHED_PROTOCOL(Sentinel, metaclass=Sentinel): - pass - - -class _SWITCH_UPGRADE(Sentinel, metaclass=Sentinel): - pass - - -class _SWITCH_CONNECT(Sentinel, metaclass=Sentinel): - pass - - -EventTransitionType = Dict[ - Type[Sentinel], - Dict[ - Type[Sentinel], - Dict[Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], Type[Sentinel]], - ], -] - -EVENT_TRIGGERED_TRANSITIONS: EventTransitionType = { - CLIENT: { - IDLE: {Request: SEND_BODY, ConnectionClosed: CLOSED}, - SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, - DONE: {ConnectionClosed: CLOSED}, - MUST_CLOSE: {ConnectionClosed: CLOSED}, - CLOSED: {ConnectionClosed: CLOSED}, - MIGHT_SWITCH_PROTOCOL: {}, - SWITCHED_PROTOCOL: {}, - ERROR: {}, - }, - SERVER: { - IDLE: { - ConnectionClosed: CLOSED, - Response: SEND_BODY, - # Special case: server sees client Request events, in this form - (Request, CLIENT): SEND_RESPONSE, - }, - SEND_RESPONSE: { - InformationalResponse: SEND_RESPONSE, - Response: SEND_BODY, - (InformationalResponse, _SWITCH_UPGRADE): SWITCHED_PROTOCOL, - (Response, _SWITCH_CONNECT): SWITCHED_PROTOCOL, - }, - SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, - DONE: {ConnectionClosed: CLOSED}, - MUST_CLOSE: {ConnectionClosed: CLOSED}, - CLOSED: {ConnectionClosed: CLOSED}, - SWITCHED_PROTOCOL: {}, - ERROR: {}, - }, -} - -StateTransitionType = Dict[ - Tuple[Type[Sentinel], Type[Sentinel]], Dict[Type[Sentinel], Type[Sentinel]] -] - -# NB: there are also some special-case state-triggered transitions hard-coded -# into _fire_state_triggered_transitions below. -STATE_TRIGGERED_TRANSITIONS: StateTransitionType = { - # (Client state, Server state) -> new states - # Protocol negotiation - (MIGHT_SWITCH_PROTOCOL, SWITCHED_PROTOCOL): {CLIENT: SWITCHED_PROTOCOL}, - # Socket shutdown - (CLOSED, DONE): {SERVER: MUST_CLOSE}, - (CLOSED, IDLE): {SERVER: MUST_CLOSE}, - (ERROR, DONE): {SERVER: MUST_CLOSE}, - (DONE, CLOSED): {CLIENT: MUST_CLOSE}, - (IDLE, CLOSED): {CLIENT: MUST_CLOSE}, - (DONE, ERROR): {CLIENT: MUST_CLOSE}, -} - - -class ConnectionState: - def __init__(self) -> None: - # Extra bits of state that don't quite fit into the state model. - - # If this is False then it enables the automatic DONE -> MUST_CLOSE - # transition. Don't set this directly; call .keep_alive_disabled() - self.keep_alive = True - - # This is a subset of {UPGRADE, CONNECT}, containing the proposals - # made by the client for switching protocols. - self.pending_switch_proposals: Set[Type[Sentinel]] = set() - - self.states: Dict[Type[Sentinel], Type[Sentinel]] = {CLIENT: IDLE, SERVER: IDLE} - - def process_error(self, role: Type[Sentinel]) -> None: - self.states[role] = ERROR - self._fire_state_triggered_transitions() - - def process_keep_alive_disabled(self) -> None: - self.keep_alive = False - self._fire_state_triggered_transitions() - - def process_client_switch_proposal(self, switch_event: Type[Sentinel]) -> None: - self.pending_switch_proposals.add(switch_event) - self._fire_state_triggered_transitions() - - def process_event( - self, - role: Type[Sentinel], - event_type: Type[Event], - server_switch_event: Optional[Type[Sentinel]] = None, - ) -> None: - _event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]] = event_type - if server_switch_event is not None: - assert role is SERVER - if server_switch_event not in self.pending_switch_proposals: - raise LocalProtocolError( - "Received server _SWITCH_UPGRADE event without a pending proposal" - ) - _event_type = (event_type, server_switch_event) - if server_switch_event is None and _event_type is Response: - self.pending_switch_proposals = set() - self._fire_event_triggered_transitions(role, _event_type) - # Special case: the server state does get to see Request - # events. - if _event_type is Request: - assert role is CLIENT - self._fire_event_triggered_transitions(SERVER, (Request, CLIENT)) - self._fire_state_triggered_transitions() - - def _fire_event_triggered_transitions( - self, - role: Type[Sentinel], - event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], - ) -> None: - state = self.states[role] - try: - new_state = EVENT_TRIGGERED_TRANSITIONS[role][state][event_type] - except KeyError: - event_type = cast(Type[Event], event_type) - raise LocalProtocolError( - "can't handle event type {} when role={} and state={}".format( - event_type.__name__, role, self.states[role] - ) - ) from None - self.states[role] = new_state - - def _fire_state_triggered_transitions(self) -> None: - # We apply these rules repeatedly until converging on a fixed point - while True: - start_states = dict(self.states) - - # It could happen that both these special-case transitions are - # enabled at the same time: - # - # DONE -> MIGHT_SWITCH_PROTOCOL - # DONE -> MUST_CLOSE - # - # For example, this will always be true of a HTTP/1.0 client - # requesting CONNECT. If this happens, the protocol switch takes - # priority. From there the client will either go to - # SWITCHED_PROTOCOL, in which case it's none of our business when - # they close the connection, or else the server will deny the - # request, in which case the client will go back to DONE and then - # from there to MUST_CLOSE. - if self.pending_switch_proposals: - if self.states[CLIENT] is DONE: - self.states[CLIENT] = MIGHT_SWITCH_PROTOCOL - - if not self.pending_switch_proposals: - if self.states[CLIENT] is MIGHT_SWITCH_PROTOCOL: - self.states[CLIENT] = DONE - - if not self.keep_alive: - for role in (CLIENT, SERVER): - if self.states[role] is DONE: - self.states[role] = MUST_CLOSE - - # Tabular state-triggered transitions - joint_state = (self.states[CLIENT], self.states[SERVER]) - changes = STATE_TRIGGERED_TRANSITIONS.get(joint_state, {}) - self.states.update(changes) - - if self.states == start_states: - # Fixed point reached - return - - def start_next_cycle(self) -> None: - if self.states != {CLIENT: DONE, SERVER: DONE}: - raise LocalProtocolError( - f"not in a reusable state. self.states={self.states}" - ) - # Can't reach DONE/DONE with any of these active, but still, let's be - # sure. - assert self.keep_alive - assert not self.pending_switch_proposals - self.states = {CLIENT: IDLE, SERVER: IDLE} diff --git a/venv/lib/python3.10/site-packages/h11/_util.py b/venv/lib/python3.10/site-packages/h11/_util.py deleted file mode 100644 index 6718445290770e028ea2f1f662026c9a0b0991db..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_util.py +++ /dev/null @@ -1,135 +0,0 @@ -from typing import Any, Dict, NoReturn, Pattern, Tuple, Type, TypeVar, Union - -__all__ = [ - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", - "validate", - "bytesify", -] - - -class ProtocolError(Exception): - """Exception indicating a violation of the HTTP/1.1 protocol. - - This as an abstract base class, with two concrete base classes: - :exc:`LocalProtocolError`, which indicates that you tried to do something - that HTTP/1.1 says is illegal, and :exc:`RemoteProtocolError`, which - indicates that the remote peer tried to do something that HTTP/1.1 says is - illegal. See :ref:`error-handling` for details. - - In addition to the normal :exc:`Exception` features, it has one attribute: - - .. attribute:: error_status_hint - - This gives a suggestion as to what status code a server might use if - this error occurred as part of a request. - - For a :exc:`RemoteProtocolError`, this is useful as a suggestion for - how you might want to respond to a misbehaving peer, if you're - implementing a server. - - For a :exc:`LocalProtocolError`, this can be taken as a suggestion for - how your peer might have responded to *you* if h11 had allowed you to - continue. - - The default is 400 Bad Request, a generic catch-all for protocol - violations. - - """ - - def __init__(self, msg: str, error_status_hint: int = 400) -> None: - if type(self) is ProtocolError: - raise TypeError("tried to directly instantiate ProtocolError") - Exception.__init__(self, msg) - self.error_status_hint = error_status_hint - - -# Strategy: there are a number of public APIs where a LocalProtocolError can -# be raised (send(), all the different event constructors, ...), and only one -# public API where RemoteProtocolError can be raised -# (receive_data()). Therefore we always raise LocalProtocolError internally, -# and then receive_data will translate this into a RemoteProtocolError. -# -# Internally: -# LocalProtocolError is the generic "ProtocolError". -# Externally: -# LocalProtocolError is for local errors and RemoteProtocolError is for -# remote errors. -class LocalProtocolError(ProtocolError): - def _reraise_as_remote_protocol_error(self) -> NoReturn: - # After catching a LocalProtocolError, use this method to re-raise it - # as a RemoteProtocolError. This method must be called from inside an - # except: block. - # - # An easy way to get an equivalent RemoteProtocolError is just to - # modify 'self' in place. - self.__class__ = RemoteProtocolError # type: ignore - # But the re-raising is somewhat non-trivial -- you might think that - # now that we've modified the in-flight exception object, that just - # doing 'raise' to re-raise it would be enough. But it turns out that - # this doesn't work, because Python tracks the exception type - # (exc_info[0]) separately from the exception object (exc_info[1]), - # and we only modified the latter. So we really do need to re-raise - # the new type explicitly. - # On py3, the traceback is part of the exception object, so our - # in-place modification preserved it and we can just re-raise: - raise self - - -class RemoteProtocolError(ProtocolError): - pass - - -def validate( - regex: Pattern[bytes], data: bytes, msg: str = "malformed data", *format_args: Any -) -> Dict[str, bytes]: - match = regex.fullmatch(data) - if not match: - if format_args: - msg = msg.format(*format_args) - raise LocalProtocolError(msg) - return match.groupdict() - - -# Sentinel values -# -# - Inherit identity-based comparison and hashing from object -# - Have a nice repr -# - Have a *bonus property*: type(sentinel) is sentinel -# -# The bonus property is useful if you want to take the return value from -# next_event() and do some sort of dispatch based on type(event). - -_T_Sentinel = TypeVar("_T_Sentinel", bound="Sentinel") - - -class Sentinel(type): - def __new__( - cls: Type[_T_Sentinel], - name: str, - bases: Tuple[type, ...], - namespace: Dict[str, Any], - **kwds: Any - ) -> _T_Sentinel: - assert bases == (Sentinel,) - v = super().__new__(cls, name, bases, namespace, **kwds) - v.__class__ = v # type: ignore - return v - - def __repr__(self) -> str: - return self.__name__ - - -# Used for methods, request targets, HTTP versions, header names, and header -# values. Accepts ascii-strings, or bytes/bytearray/memoryview/..., and always -# returns bytes. -def bytesify(s: Union[bytes, bytearray, memoryview, int, str]) -> bytes: - # Fast-path: - if type(s) is bytes: - return s - if isinstance(s, str): - s = s.encode("ascii") - if isinstance(s, int): - raise TypeError("expected bytes-like object, not int") - return bytes(s) diff --git a/venv/lib/python3.10/site-packages/h11/_version.py b/venv/lib/python3.10/site-packages/h11/_version.py deleted file mode 100644 index 76e7327b8617c9d12236f511414d5eb58e98a44b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_version.py +++ /dev/null @@ -1,16 +0,0 @@ -# This file must be kept very simple, because it is consumed from several -# places -- it is imported by h11/__init__.py, execfile'd by setup.py, etc. - -# We use a simple scheme: -# 1.0.0 -> 1.0.0+dev -> 1.1.0 -> 1.1.0+dev -# where the +dev versions are never released into the wild, they're just what -# we stick into the VCS in between releases. -# -# This is compatible with PEP 440: -# http://legacy.python.org/dev/peps/pep-0440/ -# via the use of the "local suffix" "+dev", which is disallowed on index -# servers and causes 1.0.0+dev to sort after plain 1.0.0, which is what we -# want. (Contrast with the special suffix 1.0.0.dev, which sorts *before* -# 1.0.0.) - -__version__ = "0.16.0" diff --git a/venv/lib/python3.10/site-packages/h11/_writers.py b/venv/lib/python3.10/site-packages/h11/_writers.py deleted file mode 100644 index 939cdb912a9debaea07fbf3a9ac04549c44d077c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/_writers.py +++ /dev/null @@ -1,145 +0,0 @@ -# Code to read HTTP data -# -# Strategy: each writer takes an event + a write-some-bytes function, which is -# calls. -# -# WRITERS is a dict describing how to pick a reader. It maps states to either: -# - a writer -# - or, for body writers, a dict of framin-dependent writer factories - -from typing import Any, Callable, Dict, List, Tuple, Type, Union - -from ._events import Data, EndOfMessage, Event, InformationalResponse, Request, Response -from ._headers import Headers -from ._state import CLIENT, IDLE, SEND_BODY, SEND_RESPONSE, SERVER -from ._util import LocalProtocolError, Sentinel - -__all__ = ["WRITERS"] - -Writer = Callable[[bytes], Any] - - -def write_headers(headers: Headers, write: Writer) -> None: - # "Since the Host field-value is critical information for handling a - # request, a user agent SHOULD generate Host as the first header field - # following the request-line." - RFC 7230 - raw_items = headers._full_items - for raw_name, name, value in raw_items: - if name == b"host": - write(b"%s: %s\r\n" % (raw_name, value)) - for raw_name, name, value in raw_items: - if name != b"host": - write(b"%s: %s\r\n" % (raw_name, value)) - write(b"\r\n") - - -def write_request(request: Request, write: Writer) -> None: - if request.http_version != b"1.1": - raise LocalProtocolError("I only send HTTP/1.1") - write(b"%s %s HTTP/1.1\r\n" % (request.method, request.target)) - write_headers(request.headers, write) - - -# Shared between InformationalResponse and Response -def write_any_response( - response: Union[InformationalResponse, Response], write: Writer -) -> None: - if response.http_version != b"1.1": - raise LocalProtocolError("I only send HTTP/1.1") - status_bytes = str(response.status_code).encode("ascii") - # We don't bother sending ascii status messages like "OK"; they're - # optional and ignored by the protocol. (But the space after the numeric - # status code is mandatory.) - # - # XX FIXME: could at least make an effort to pull out the status message - # from stdlib's http.HTTPStatus table. Or maybe just steal their enums - # (either by import or copy/paste). We already accept them as status codes - # since they're of type IntEnum < int. - write(b"HTTP/1.1 %s %s\r\n" % (status_bytes, response.reason)) - write_headers(response.headers, write) - - -class BodyWriter: - def __call__(self, event: Event, write: Writer) -> None: - if type(event) is Data: - self.send_data(event.data, write) - elif type(event) is EndOfMessage: - self.send_eom(event.headers, write) - else: # pragma: no cover - assert False - - def send_data(self, data: bytes, write: Writer) -> None: - pass - - def send_eom(self, headers: Headers, write: Writer) -> None: - pass - - -# -# These are all careful not to do anything to 'data' except call len(data) and -# write(data). This allows us to transparently pass-through funny objects, -# like placeholder objects referring to files on disk that will be sent via -# sendfile(2). -# -class ContentLengthWriter(BodyWriter): - def __init__(self, length: int) -> None: - self._length = length - - def send_data(self, data: bytes, write: Writer) -> None: - self._length -= len(data) - if self._length < 0: - raise LocalProtocolError("Too much data for declared Content-Length") - write(data) - - def send_eom(self, headers: Headers, write: Writer) -> None: - if self._length != 0: - raise LocalProtocolError("Too little data for declared Content-Length") - if headers: - raise LocalProtocolError("Content-Length and trailers don't mix") - - -class ChunkedWriter(BodyWriter): - def send_data(self, data: bytes, write: Writer) -> None: - # if we encoded 0-length data in the naive way, it would look like an - # end-of-message. - if not data: - return - write(b"%x\r\n" % len(data)) - write(data) - write(b"\r\n") - - def send_eom(self, headers: Headers, write: Writer) -> None: - write(b"0\r\n") - write_headers(headers, write) - - -class Http10Writer(BodyWriter): - def send_data(self, data: bytes, write: Writer) -> None: - write(data) - - def send_eom(self, headers: Headers, write: Writer) -> None: - if headers: - raise LocalProtocolError("can't send trailers to HTTP/1.0 client") - # no need to close the socket ourselves, that will be taken care of by - # Connection: close machinery - - -WritersType = Dict[ - Union[Tuple[Type[Sentinel], Type[Sentinel]], Type[Sentinel]], - Union[ - Dict[str, Type[BodyWriter]], - Callable[[Union[InformationalResponse, Response], Writer], None], - Callable[[Request, Writer], None], - ], -] - -WRITERS: WritersType = { - (CLIENT, IDLE): write_request, - (SERVER, IDLE): write_any_response, - (SERVER, SEND_RESPONSE): write_any_response, - SEND_BODY: { - "chunked": ChunkedWriter, - "content-length": ContentLengthWriter, - "http/1.0": Http10Writer, - }, -} diff --git a/venv/lib/python3.10/site-packages/h11/py.typed b/venv/lib/python3.10/site-packages/h11/py.typed deleted file mode 100644 index f5642f79f21d872f010979dcf6f0c4a415acc19d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/h11/py.typed +++ /dev/null @@ -1 +0,0 @@ -Marker diff --git a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/METADATA b/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/METADATA deleted file mode 100644 index 092b5b25e2baf8f2c506ffef7e2378e72ef6ccb1..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/METADATA +++ /dev/null @@ -1,87 +0,0 @@ -Metadata-Version: 2.4 -Name: hf-xet -Version: 1.3.1 -Classifier: Development Status :: 5 - Production/Stable -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Rust -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Free Threading -Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta -Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence -Requires-Dist: pytest ; extra == 'tests' -Provides-Extra: tests -License-File: LICENSE -Summary: Fast transfer of large files with the Hugging Face Hub. -Maintainer-email: Rajat Arya , Jared Sulzdorf , Di Xiao , Assaf Vayner , Hoyt Koepke -License-Expression: Apache-2.0 -Requires-Python: >=3.8 -Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM -Project-URL: Documentation, https://huggingface.co/docs/hub/xet/index -Project-URL: Homepage, https://github.com/huggingface/xet-core -Project-URL: Issues, https://github.com/huggingface/xet-core/issues -Project-URL: Repository, https://github.com/huggingface/xet-core.git - - -

- License - GitHub release - Contributor Covenant -

- -

-

🤗 hf-xet - xet client tech, used in huggingface_hub

-

- -## Welcome - -`hf-xet` enables `huggingface_hub` to utilize xet storage for uploading and downloading to HF Hub. Xet storage provides chunk-based deduplication, efficient storage/retrieval with local disk caching, and backwards compatibility with Git LFS. This library is not meant to be used directly, and is instead intended to be used from [huggingface_hub](https://pypi.org/project/huggingface-hub). - -## Key features - -♻ **chunk-based deduplication implementation**: avoid transferring and storing chunks that are shared across binary files (models, datasets, etc). - -🤗 **Python bindings**: bindings for [huggingface_hub](https://github.com/huggingface/huggingface_hub/) package. - -↔ **network communications**: concurrent communication to HF Hub Xet backend services (CAS). - -🔖 **local disk caching**: chunk-based cache that sits alongside the existing [huggingface_hub disk cache](https://huggingface.co/docs/huggingface_hub/guides/manage-cache). - -## Installation - -Install the `hf_xet` package with [pip](https://pypi.org/project/hf-xet/): - -```bash -pip install hf_xet -``` - -## Quick Start - -`hf_xet` is not intended to be run independently as it is expected to be used from `huggingface_hub`, so to get started with `huggingface_hub` check out the documentation [here]("https://hf.co/docs/huggingface_hub"). - -## Contributions (feature requests, bugs, etc.) are encouraged & appreciated 💙💚💛💜🧡❤️ - -Please join us in making hf-xet better. We value everyone's contributions. Code is not the only way to help. Answering questions, helping each other, improving documentation, filing issues all help immensely. If you are interested in contributing (please do!), check out the [contribution guide](https://github.com/huggingface/xet-core/blob/main/CONTRIBUTING.md) for this repository. diff --git a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/RECORD b/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/RECORD deleted file mode 100644 index 142b0a6908cb8680aa913f10c1c493ed5e3d0fd8..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/RECORD +++ /dev/null @@ -1,9 +0,0 @@ -hf_xet-1.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -hf_xet-1.3.1.dist-info/METADATA,sha256=c8EMP8rcGk7-_0Pyg8YiB_La4qawIVQTc8NKjf9Z6Cw,4882 -hf_xet-1.3.1.dist-info/RECORD,, -hf_xet-1.3.1.dist-info/WHEEL,sha256=ycZRBBQNh-_vBSCR_X0ck7NlL8NDEI7G-tWH-Cjb8uw,143 -hf_xet-1.3.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357 -hf_xet-1.3.1.dist-info/sboms/hf_xet.cyclonedx.json,sha256=lvKUn39ZTtvl0XcofThR8x3TLhsIqk0bst_qM1-uTJ0,394826 -hf_xet/__init__.py,sha256=E8UDdyQ8glZ_nve9hHEf22bPang8-RKx4VuApXYeQUo,107 -hf_xet/__pycache__/__init__.cpython-310.pyc,, -hf_xet/hf_xet.abi3.so,sha256=rNWSxzRlW0YzjOwRfMAgzAE80HXbAW3_HR8nas-2WOg,10589672 diff --git a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/WHEEL b/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/WHEEL deleted file mode 100644 index e3c7eedd8e94fbe7277127c82058423fa8d80b38..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: maturin (1.12.4) -Root-Is-Purelib: false -Tag: cp37-abi3-manylinux_2_17_x86_64 -Tag: cp37-abi3-manylinux2014_x86_64 diff --git a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/licenses/LICENSE deleted file mode 100644 index 261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/sboms/hf_xet.cyclonedx.json b/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/sboms/hf_xet.cyclonedx.json deleted file mode 100644 index d4a65a054762366d7ea12295ca099b7e2ac3f296..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet-1.3.1.dist-info/sboms/hf_xet.cyclonedx.json +++ /dev/null @@ -1,12019 +0,0 @@ -{ - "bomFormat": "CycloneDX", - "specVersion": "1.5", - "version": 1, - "serialNumber": "urn:uuid:ede838f0-3b72-4297-b920-6a643907fcf7", - "metadata": { - "timestamp": "2026-02-25T00:48:53.825889783Z", - "tools": [ - { - "vendor": "CycloneDX", - "name": "cargo-cyclonedx", - "version": "0.5.7" - } - ], - "component": { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/hf_xet#1.3.1", - "name": "hf_xet", - "version": "1.3.1", - "scope": "required", - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/hf_xet@1.3.1?download_url=file://.", - "components": [ - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/hf_xet#1.3.1 bin-target-0", - "name": "hf_xet", - "version": "1.3.1", - "purl": "pkg:cargo/hf_xet@1.3.1?download_url=file://.#src/lib.rs" - } - ] - }, - "properties": [ - { - "name": "cdx:rustc:sbom:target:all_targets", - "value": "true" - } - ] - }, - "components": [ - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/cas_client#0.14.5", - "name": "cas_client", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/cas_client@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/cas_client" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/cas_object#0.1.0", - "name": "cas_object", - "version": "0.1.0", - "scope": "required", - "purl": "pkg:cargo/cas_object@0.1.0?download_url=file:///home/runner/work/xet-core/xet-core/cas_object" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/cas_types#0.1.0", - "name": "cas_types", - "version": "0.1.0", - "scope": "required", - "purl": "pkg:cargo/cas_types@0.1.0?download_url=file:///home/runner/work/xet-core/xet-core/cas_types" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/data#0.14.5", - "name": "data", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/data@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/data" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/deduplication#0.14.5", - "name": "deduplication", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/deduplication@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/deduplication" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "name": "error_printer", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/error_printer@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/error_printer" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/file_reconstruction#0.14.5", - "name": "file_reconstruction", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/file_reconstruction@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/file_reconstruction" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/file_utils#0.14.2", - "name": "file_utils", - "version": "0.14.2", - "scope": "required", - "purl": "pkg:cargo/file_utils@0.14.2?download_url=file:///home/runner/work/xet-core/xet-core/file_utils" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/hub_client#0.1.0", - "name": "hub_client", - "version": "0.1.0", - "scope": "required", - "purl": "pkg:cargo/hub_client@0.1.0?download_url=file:///home/runner/work/xet-core/xet-core/hub_client" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/mdb_shard#0.14.5", - "name": "mdb_shard", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/mdb_shard@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/mdb_shard" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "name": "merklehash", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/merklehash@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/merklehash" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/progress_tracking#0.1.0", - "name": "progress_tracking", - "version": "0.1.0", - "scope": "required", - "purl": "pkg:cargo/progress_tracking@0.1.0?download_url=file:///home/runner/work/xet-core/xet-core/progress_tracking" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "name": "utils", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/utils@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/utils" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/xet_config#0.14.5", - "name": "xet_config", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/xet_config@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/xet_config" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/xet_logging#0.14.5", - "name": "xet_logging", - "version": "0.14.5", - "scope": "required", - "purl": "pkg:cargo/xet_logging@0.14.5?download_url=file:///home/runner/work/xet-core/xet-core/xet_logging" - }, - { - "type": "library", - "bom-ref": "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0", - "name": "xet_runtime", - "version": "0.1.0", - "scope": "required", - "purl": "pkg:cargo/xet_runtime@0.1.0?download_url=file:///home/runner/work/xet-core/xet-core/xet_runtime" - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.4", - "author": "Andrew Gallant ", - "name": "aho-corasick", - "version": "1.1.4", - "description": "Fast multiple substring searching.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT" - } - ], - "purl": "pkg:cargo/aho-corasick@1.1.4", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/BurntSushi/aho-corasick" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/aho-corasick" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#anstream@0.6.21", - "name": "anstream", - "version": "0.6.21", - "description": "IO stream adapters for writing colored text that will gracefully degrade according to your terminal's capabilities.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/anstream@0.6.21", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-cli/anstyle.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#anstyle-parse@0.2.7", - "name": "anstyle-parse", - "version": "0.2.7", - "description": "Parse ANSI Style Escapes", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/anstyle-parse@0.2.7", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-cli/anstyle.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#anstyle-query@1.1.5", - "name": "anstyle-query", - "version": "1.1.5", - "description": "Look up colored console capabilities", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/anstyle-query@1.1.5", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-cli/anstyle.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#anstyle@1.0.13", - "name": "anstyle", - "version": "1.0.13", - "description": "ANSI text styling", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/anstyle@1.0.13", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-cli/anstyle.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "author": "David Tolnay ", - "name": "anyhow", - "version": "1.0.101", - "description": "Flexible concrete Error type built on std::error::Error", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/anyhow@1.0.101", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/anyhow" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/anyhow" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#approx@0.5.1", - "author": "Brendan Zabarauskas ", - "name": "approx", - "version": "0.5.1", - "description": "Approximate floating point equality comparisons and assertions.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/approx@0.5.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/approx" - }, - { - "type": "website", - "url": "https://github.com/brendanzab/approx" - }, - { - "type": "vcs", - "url": "https://github.com/brendanzab/approx" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#arrayref@0.3.9", - "author": "David Roundy ", - "name": "arrayref", - "version": "0.3.9", - "description": "Macros to take array references of slices", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - } - ], - "licenses": [ - { - "expression": "BSD-2-Clause" - } - ], - "purl": "pkg:cargo/arrayref@0.3.9", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/arrayref" - }, - { - "type": "vcs", - "url": "https://github.com/droundy/arrayref" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#arrayvec@0.7.6", - "author": "bluss", - "name": "arrayvec", - "version": "0.7.6", - "description": "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/arrayvec@0.7.6", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/arrayvec/" - }, - { - "type": "vcs", - "url": "https://github.com/bluss/arrayvec" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "author": "David Tolnay ", - "name": "async-trait", - "version": "0.1.89", - "description": "Type erasure for async trait methods", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/async-trait@0.1.89", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/async-trait" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/async-trait" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#atomic-waker@1.1.2", - "author": "Stjepan Glavina , Contributors to futures-rs", - "name": "atomic-waker", - "version": "1.1.2", - "description": "A synchronization primitive for task wakeup", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/atomic-waker@1.1.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/smol-rs/atomic-waker" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.5.0", - "author": "Josh Stone ", - "name": "autocfg", - "version": "1.5.0", - "description": "Automatic cfg for Rust compiler features", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/autocfg@1.5.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/autocfg/" - }, - { - "type": "vcs", - "url": "https://github.com/cuviper/autocfg" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#aws-lc-rs@1.15.4", - "author": "AWS-LibCrypto", - "name": "aws-lc-rs", - "version": "1.15.4", - "description": "aws-lc-rs is a cryptographic library using AWS-LC for its cryptographic operations. This library strives to be API-compatible with the popular Rust library named ring.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" - } - ], - "licenses": [ - { - "expression": "ISC AND (Apache-2.0 OR ISC)" - } - ], - "purl": "pkg:cargo/aws-lc-rs@1.15.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/crate/aws-lc-rs" - }, - { - "type": "website", - "url": "https://github.com/aws/aws-lc-rs" - }, - { - "type": "other", - "url": "aws_lc_rs_1_15_4_sys" - }, - { - "type": "vcs", - "url": "https://github.com/aws/aws-lc-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#aws-lc-sys@0.37.0", - "author": "AWS-LC", - "name": "aws-lc-sys", - "version": "0.37.0", - "description": "AWS-LC is a general-purpose cryptographic library maintained by the AWS Cryptography team for AWS and their customers. It іs based on code from the Google BoringSSL project and the OpenSSL project.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a" - } - ], - "licenses": [ - { - "expression": "ISC AND (Apache-2.0 OR ISC) AND OpenSSL" - } - ], - "purl": "pkg:cargo/aws-lc-sys@0.37.0", - "externalReferences": [ - { - "type": "other", - "url": "aws_lc_0_37_0" - }, - { - "type": "vcs", - "url": "https://github.com/aws/aws-lc-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#axum-core@0.5.6", - "name": "axum-core", - "version": "0.5.6", - "description": "Core types and traits for axum", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/axum-core@0.5.6", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/tokio-rs/axum" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/axum" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#axum@0.8.8", - "name": "axum", - "version": "0.8.8", - "description": "Web framework that focuses on ergonomics and modularity", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/axum@0.8.8", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/tokio-rs/axum" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/axum" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "author": "Marshall Pierce ", - "name": "base64", - "version": "0.22.1", - "description": "encodes and decodes base64 as bytes or utf8", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/base64@0.22.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/base64" - }, - { - "type": "vcs", - "url": "https://github.com/marshallpierce/rust-base64" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bincode@1.3.3", - "author": "Ty Overby , Francesco Mazzoli , David Tolnay , Zoey Riordan ", - "name": "bincode", - "version": "1.3.3", - "description": "A binary serialization / deserialization strategy that uses Serde for transforming structs into bytes and vice versa!", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/bincode@1.3.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/bincode" - }, - { - "type": "vcs", - "url": "https://github.com/servo/bincode" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.10.0", - "author": "The Rust Project Developers", - "name": "bitflags", - "version": "2.10.0", - "description": "A macro to generate structures which behave like bitflags. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/bitflags@2.10.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/bitflags" - }, - { - "type": "website", - "url": "https://github.com/bitflags/bitflags" - }, - { - "type": "vcs", - "url": "https://github.com/bitflags/bitflags" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#blake3@1.8.3", - "author": "Jack O'Connor , Samuel Neves", - "name": "blake3", - "version": "1.8.3", - "description": "the BLAKE3 hash function", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" - } - ], - "licenses": [ - { - "expression": "CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception" - } - ], - "purl": "pkg:cargo/blake3@1.8.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/blake3" - }, - { - "type": "vcs", - "url": "https://github.com/BLAKE3-team/BLAKE3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#block-buffer@0.10.4", - "author": "RustCrypto Developers", - "name": "block-buffer", - "version": "0.10.4", - "description": "Buffer type for block processing of data", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/block-buffer@0.10.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/block-buffer" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/utils" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bstr@1.12.1", - "author": "Andrew Gallant ", - "name": "bstr", - "version": "1.12.1", - "description": "A string type that is not required to be valid UTF-8.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/bstr@1.12.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/bstr" - }, - { - "type": "website", - "url": "https://github.com/BurntSushi/bstr" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/bstr" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bytemuck@1.25.0", - "author": "Lokathor ", - "name": "bytemuck", - "version": "1.25.0", - "description": "A crate for mucking around with piles of bytes.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" - } - ], - "licenses": [ - { - "expression": "Zlib OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/bytemuck@1.25.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Lokathor/bytemuck" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#byteorder@1.5.0", - "author": "Andrew Gallant ", - "name": "byteorder", - "version": "1.5.0", - "description": "Library for reading/writing numbers in big-endian and little-endian.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT" - } - ], - "purl": "pkg:cargo/byteorder@1.5.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/byteorder" - }, - { - "type": "website", - "url": "https://github.com/BurntSushi/byteorder" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/byteorder" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "author": "Carl Lerche , Sean McArthur ", - "name": "bytes", - "version": "1.11.1", - "description": "Types and traits for working with bytes", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/bytes@1.11.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/tokio-rs/bytes" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55", - "author": "Alex Crichton ", - "name": "cc", - "version": "1.2.55", - "description": "A build-time dependency for Cargo build scripts to assist in invoking the native C compiler to compile native C code into a static archive to be linked into Rust code. ", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/cc@1.2.55", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/cc" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/cc-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/cc-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@0.1.10", - "author": "Alex Crichton ", - "name": "cfg-if", - "version": "0.1.10", - "description": "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/cfg-if@0.1.10", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/cfg-if" - }, - { - "type": "website", - "url": "https://github.com/alexcrichton/cfg-if" - }, - { - "type": "vcs", - "url": "https://github.com/alexcrichton/cfg-if" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "author": "Alex Crichton ", - "name": "cfg-if", - "version": "1.0.4", - "description": "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/cfg-if@1.0.4", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-lang/cfg-if" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cfg_aliases@0.2.1", - "author": "Zicklag ", - "name": "cfg_aliases", - "version": "0.2.1", - "description": "A tiny utility to help save you a lot of effort with long winded `#[cfg()]` checks.", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/cfg_aliases@0.2.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/cfg_aliases" - }, - { - "type": "website", - "url": "https://github.com/katharostech/cfg_aliases" - }, - { - "type": "vcs", - "url": "https://github.com/katharostech/cfg_aliases" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "name": "chrono", - "version": "0.4.43", - "description": "Date and time library for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/chrono@0.4.43", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/chrono/" - }, - { - "type": "website", - "url": "https://github.com/chronotope/chrono" - }, - { - "type": "vcs", - "url": "https://github.com/chronotope/chrono" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#clap@4.5.57", - "name": "clap", - "version": "4.5.57", - "description": "A simple to use, efficient, and full-featured Command Line Argument Parser", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/clap@4.5.57", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/clap-rs/clap" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#clap_builder@4.5.57", - "name": "clap_builder", - "version": "4.5.57", - "description": "A simple to use, efficient, and full-featured Command Line Argument Parser", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/clap_builder@4.5.57", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/clap-rs/clap" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#clap_derive@4.5.55", - "name": "clap_derive", - "version": "4.5.55", - "description": "Parse command line argument by defining a struct, derive crate.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/clap_derive@4.5.55", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/clap-rs/clap" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#clap_lex@0.7.7", - "name": "clap_lex", - "version": "0.7.7", - "description": "Minimal, flexible command line parser", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/clap_lex@0.7.7", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/clap-rs/clap" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cmake@0.1.57", - "author": "Alex Crichton ", - "name": "cmake", - "version": "0.1.57", - "description": "A build dependency for running `cmake` to build a native library ", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/cmake@0.1.57", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/cmake" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/cmake-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/cmake-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#colorchoice@1.0.4", - "name": "colorchoice", - "version": "1.0.4", - "description": "Global override of color control", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/colorchoice@1.0.4", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-cli/anstyle.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#colored@3.1.1", - "author": "Thomas Wickham ", - "name": "colored", - "version": "3.1.1", - "description": "The most simple way to add colors in your terminal", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" - } - ], - "licenses": [ - { - "expression": "MPL-2.0" - } - ], - "purl": "pkg:cargo/colored@3.1.1", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/mackwic/colored" - }, - { - "type": "vcs", - "url": "https://github.com/mackwic/colored" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#const-str@1.1.0", - "author": "Nugine ", - "name": "const-str", - "version": "1.1.0", - "description": "compile-time string operations", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/const-str@1.1.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Nugine/const-str" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#const_panic@0.2.15", - "author": "rodrimati1992 ", - "name": "const_panic", - "version": "0.2.15", - "description": "const panic with formatting", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e262cdaac42494e3ae34c43969f9cdeb7da178bdb4b66fa6a1ea2edb4c8ae652" - } - ], - "licenses": [ - { - "expression": "Zlib" - } - ], - "purl": "pkg:cargo/const_panic@0.2.15", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rodrimati1992/const_panic/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#constant_time_eq@0.4.2", - "author": "Cesar Eduardo Barros ", - "name": "constant_time_eq", - "version": "0.4.2", - "description": "Compares two equal-sized byte strings in constant time.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" - } - ], - "licenses": [ - { - "expression": "CC0-1.0 OR MIT-0 OR Apache-2.0" - } - ], - "purl": "pkg:cargo/constant_time_eq@0.4.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/constant_time_eq" - }, - { - "type": "vcs", - "url": "https://github.com/cesarb/constant_time_eq" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#countio@0.3.0", - "author": "Oleh Martsokha ", - "name": "countio", - "version": "0.3.0", - "description": "Byte counting for std::io::{Read, Write, Seek} and its async variants from futures and tokio. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b9702aee5d1d744c01d82f6915644f950f898e014903385464c773b96fefdecb" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/countio@0.3.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/countio" - }, - { - "type": "website", - "url": "https://github.com/spire-rs/countio" - }, - { - "type": "vcs", - "url": "https://github.com/spire-rs/countio" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cpufeatures@0.2.17", - "author": "RustCrypto Developers", - "name": "cpufeatures", - "version": "0.2.17", - "description": "Lightweight runtime CPU feature detection for aarch64, loongarch64, and x86/x86_64 targets, with no_std support and support for mobile targets including Android and iOS ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/cpufeatures@0.2.17", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/cpufeatures" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/utils" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#crossbeam-channel@0.5.15", - "name": "crossbeam-channel", - "version": "0.5.15", - "description": "Multi-producer multi-consumer channels for message passing", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/crossbeam-channel@0.5.15", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" - }, - { - "type": "vcs", - "url": "https://github.com/crossbeam-rs/crossbeam" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#crossbeam-queue@0.3.12", - "name": "crossbeam-queue", - "version": "0.3.12", - "description": "Concurrent queues", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/crossbeam-queue@0.3.12", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue" - }, - { - "type": "vcs", - "url": "https://github.com/crossbeam-rs/crossbeam" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.21", - "name": "crossbeam-utils", - "version": "0.8.21", - "description": "Utilities for concurrent programming", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/crossbeam-utils@0.8.21", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" - }, - { - "type": "vcs", - "url": "https://github.com/crossbeam-rs/crossbeam" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#crypto-common@0.1.7", - "author": "RustCrypto Developers", - "name": "crypto-common", - "version": "0.1.7", - "description": "Common cryptographic traits", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/crypto-common@0.1.7", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/crypto-common" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/traits" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#csv-core@0.1.13", - "author": "Andrew Gallant ", - "name": "csv-core", - "version": "0.1.13", - "description": "Bare bones CSV parsing with no_std support.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT" - } - ], - "purl": "pkg:cargo/csv-core@0.1.13", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/csv-core" - }, - { - "type": "website", - "url": "https://github.com/BurntSushi/rust-csv" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/rust-csv" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#csv@1.4.0", - "author": "Andrew Gallant ", - "name": "csv", - "version": "1.4.0", - "description": "Fast CSV parsing with support for serde.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT" - } - ], - "purl": "pkg:cargo/csv@1.4.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/csv" - }, - { - "type": "website", - "url": "https://github.com/BurntSushi/rust-csv" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/rust-csv" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ctor-proc-macro@0.0.7", - "author": "Matt Mastracci ", - "name": "ctor-proc-macro", - "version": "0.0.7", - "description": "proc-macro support for the ctor crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/ctor-proc-macro@0.0.7", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/mmastrac/rust-ctor" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ctor@0.6.3", - "author": "Matt Mastracci ", - "name": "ctor", - "version": "0.6.3", - "description": "__attribute__((constructor)) for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/ctor@0.6.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/mmastrac/rust-ctor" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#deranged@0.5.5", - "author": "Jacob Pratt ", - "name": "deranged", - "version": "0.5.5", - "description": "Ranged integers", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/deranged@0.5.5", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/jhpratt/deranged" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#derivative@2.2.0", - "author": "mcarton ", - "name": "derivative", - "version": "2.2.0", - "description": "A set of alternative `derive` attributes for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/derivative@2.2.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://mcarton.github.io/rust-derivative/" - }, - { - "type": "vcs", - "url": "https://github.com/mcarton/rust-derivative" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#digest@0.10.7", - "author": "RustCrypto Developers", - "name": "digest", - "version": "0.10.7", - "description": "Traits for cryptographic hash functions and message authentication codes", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/digest@0.10.7", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/digest" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/traits" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#dirs-sys@0.5.0", - "author": "Simon Ochsenreither ", - "name": "dirs-sys", - "version": "0.5.0", - "description": "System-level helper functions for the dirs and directories crates.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/dirs-sys@0.5.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/dirs-dev/dirs-sys-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#dirs@6.0.0", - "author": "Simon Ochsenreither ", - "name": "dirs", - "version": "6.0.0", - "description": "A tiny low-level library that provides platform-specific standard locations of directories for config, cache and other data on Linux, Windows, macOS and Redox by leveraging the mechanisms defined by the XDG base/user directory specifications on Linux, the Known Folder API on Windows, and the Standard Directory guidelines on macOS.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/dirs@6.0.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/soc/dirs-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", - "author": "Jane Lusby ", - "name": "displaydoc", - "version": "0.2.5", - "description": "A derive macro for implementing the display Trait via a doc comment and string interpolation ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/displaydoc@0.2.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/displaydoc" - }, - { - "type": "website", - "url": "https://github.com/yaahc/displaydoc" - }, - { - "type": "vcs", - "url": "https://github.com/yaahc/displaydoc" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#doxygen-rs@0.4.2", - "name": "doxygen-rs", - "version": "0.4.2", - "description": "Transform Doxygen to Rustdoc", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "415b6ec780d34dcf624666747194393603d0373b7141eef01d12ee58881507d9" - } - ], - "licenses": [ - { - "expression": "BSD-3-Clause" - } - ], - "purl": "pkg:cargo/doxygen-rs@0.4.2", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/Techie-Pi/doxygen-rs/" - }, - { - "type": "vcs", - "url": "https://github.com/Techie-Pi/doxygen-rs/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#dtor-proc-macro@0.0.6", - "author": "Matt Mastracci ", - "name": "dtor-proc-macro", - "version": "0.0.6", - "description": "proc-macro support for the dtor crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/dtor-proc-macro@0.0.6", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/mmastrac/rust-ctor" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#dtor@0.1.1", - "author": "Matt Mastracci ", - "name": "dtor", - "version": "0.1.1", - "description": "__attribute__((destructor)) for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/dtor@0.1.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/mmastrac/rust-ctor" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#dunce@1.0.5", - "author": "Kornel ", - "name": "dunce", - "version": "1.0.5", - "description": "Normalize Windows paths to the most compatible format, avoiding UNC where possible", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - } - ], - "licenses": [ - { - "expression": "CC0-1.0 OR MIT-0 OR Apache-2.0" - } - ], - "purl": "pkg:cargo/dunce@1.0.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/dunce" - }, - { - "type": "website", - "url": "https://lib.rs/crates/dunce" - }, - { - "type": "vcs", - "url": "https://gitlab.com/kornelski/dunce" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#duration-str@0.19.0", - "author": "baoyachi ", - "name": "duration-str", - "version": "0.19.0", - "description": "duration string parser", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "12494809f9915b6132014cc259c4e204ab53ab6c6dd2225672703b5359267d82" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/duration-str@0.19.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/baoyachi/duration-str" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#either@1.15.0", - "author": "bluss", - "name": "either", - "version": "1.15.0", - "description": "The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/either@1.15.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/either/1/" - }, - { - "type": "vcs", - "url": "https://github.com/rayon-rs/either" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#equivalent@1.0.2", - "name": "equivalent", - "version": "1.0.2", - "description": "Traits for key comparison in maps.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/equivalent@1.0.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/indexmap-rs/equivalent" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#errno@0.3.14", - "author": "Chris Wong , Dan Gohman ", - "name": "errno", - "version": "0.3.14", - "description": "Cross-platform interface to the `errno` variable.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/errno@0.3.14", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/errno" - }, - { - "type": "vcs", - "url": "https://github.com/lambda-fairy/rust-errno" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#fastrand@2.3.0", - "author": "Stjepan Glavina ", - "name": "fastrand", - "version": "2.3.0", - "description": "A simple and fast random number generator", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/fastrand@2.3.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/smol-rs/fastrand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9", - "name": "find-msvc-tools", - "version": "0.1.9", - "description": "Find windows-specific tools, read MSVC versions from the registry and from COM interfaces", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/find-msvc-tools@0.1.9", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/find-msvc-tools" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/cc-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#fnv@1.0.7", - "author": "Alex Crichton ", - "name": "fnv", - "version": "1.0.7", - "description": "Fowler–Noll–Vo hash function", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/fnv@1.0.7", - "externalReferences": [ - { - "type": "documentation", - "url": "https://doc.servo.org/fnv/" - }, - { - "type": "vcs", - "url": "https://github.com/servo/rust-fnv" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", - "author": "The rust-url developers", - "name": "form_urlencoded", - "version": "1.2.2", - "description": "Parser and serializer for the application/x-www-form-urlencoded syntax, as used by HTML forms.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/form_urlencoded@1.2.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/servo/rust-url" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#fs_extra@1.3.0", - "author": "Denis Kurilenko ", - "name": "fs_extra", - "version": "1.3.0", - "description": "Expanding std::fs and std::io. Recursively copy folders with information about process and much more.", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/fs_extra@1.3.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/fs_extra" - }, - { - "type": "website", - "url": "https://github.com/webdesus/fs_extra" - }, - { - "type": "vcs", - "url": "https://github.com/webdesus/fs_extra" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-channel@0.3.31", - "name": "futures-channel", - "version": "0.3.31", - "description": "Channels for asynchronous communication using futures-rs. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-channel@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "name": "futures-core", - "version": "0.3.31", - "description": "The core traits and types in for the `futures` library. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-core@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-executor@0.3.31", - "name": "futures-executor", - "version": "0.3.31", - "description": "Executors for asynchronous tasks based on the futures-rs library. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-executor@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-io@0.3.31", - "name": "futures-io", - "version": "0.3.31", - "description": "The `AsyncRead`, `AsyncWrite`, `AsyncSeek`, and `AsyncBufRead` traits for the futures-rs library. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-io@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-macro@0.3.31", - "name": "futures-macro", - "version": "0.3.31", - "description": "The futures-rs procedural macro implementations. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-macro@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.31", - "name": "futures-sink", - "version": "0.3.31", - "description": "The asynchronous `Sink` trait for the futures-rs library. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-sink@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-task@0.3.31", - "name": "futures-task", - "version": "0.3.31", - "description": "Tools for working with tasks. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-task@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "name": "futures-util", - "version": "0.3.31", - "description": "Common utilities and extension traits for the futures-rs library. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures-util@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#futures@0.3.31", - "name": "futures", - "version": "0.3.31", - "description": "An implementation of futures and streams featuring zero allocations, composability, and iterator-like interfaces. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/futures@0.3.31", - "externalReferences": [ - { - "type": "website", - "url": "https://rust-lang.github.io/futures-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/futures-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#gearhash@0.1.3", - "author": "Sam Rijs ", - "name": "gearhash", - "version": "0.1.3", - "description": "Fast, SIMD-accelerated hash function for content-defined chunking", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c8cf82cf76cd16485e56295a1377c775ce708c9f1a0be6b029076d60a245d213" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/gearhash@0.1.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/srijs/rust-gearhash" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#generic-array@0.14.7", - "author": "Bartłomiej Kamiński , Aaron Trent ", - "name": "generic-array", - "version": "0.14.7", - "description": "Generic types implementing functionality of arrays", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/generic-array@0.14.7", - "externalReferences": [ - { - "type": "documentation", - "url": "http://fizyk20.github.io/generic-array/generic_array/" - }, - { - "type": "vcs", - "url": "https://github.com/fizyk20/generic-array.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.2.17", - "author": "The Rand Project Developers", - "name": "getrandom", - "version": "0.2.17", - "description": "A small cross-platform library for retrieving random data from system source", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/getrandom@0.2.17", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/getrandom" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/getrandom" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.3.4", - "author": "The Rand Project Developers", - "name": "getrandom", - "version": "0.3.4", - "description": "A small cross-platform library for retrieving random data from system source", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/getrandom@0.3.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/getrandom" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/getrandom" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.4.1", - "author": "The Rand Project Developers", - "name": "getrandom", - "version": "0.4.1", - "description": "A small cross-platform library for retrieving random data from system source", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/getrandom@0.4.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/getrandom" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/getrandom" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#git-version-macro@0.3.9", - "author": "David Roundy , Maarten de Vries , Mara Bos ", - "name": "git-version-macro", - "version": "0.3.9", - "description": "Internal macro crate for git-version.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" - } - ], - "licenses": [ - { - "expression": "BSD-2-Clause" - } - ], - "purl": "pkg:cargo/git-version-macro@0.3.9", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/fusion-engineering/rust-git-version" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#git-version@0.3.9", - "author": "Mara Bos , Maarten de Vries , David Roundy ", - "name": "git-version", - "version": "0.3.9", - "description": "Compile the git version (tag name, or hash otherwise) and dirty state into your program.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" - } - ], - "licenses": [ - { - "expression": "BSD-2-Clause" - } - ], - "purl": "pkg:cargo/git-version@0.3.9", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/git-version/" - }, - { - "type": "vcs", - "url": "https://github.com/fusion-engineering/rust-git-version" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#h2@0.4.13", - "author": "Carl Lerche , Sean McArthur ", - "name": "h2", - "version": "0.4.13", - "description": "An HTTP/2 client and server", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/h2@0.4.13", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/h2" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/h2" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#half@2.7.1", - "author": "Kathryn Long ", - "name": "half", - "version": "2.7.1", - "description": "Half-precision floating point f16 and bf16 types for Rust implementing the IEEE 754-2008 standard binary16 and bfloat16 types.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/half@2.7.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/VoidStarKat/half-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.16.1", - "author": "Amanieu d'Antras ", - "name": "hashbrown", - "version": "0.16.1", - "description": "A Rust port of Google's SwissTable hash map", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/hashbrown@0.16.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-lang/hashbrown" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#headers-core@0.3.0", - "author": "Sean McArthur ", - "name": "headers-core", - "version": "0.3.0", - "description": "typed HTTP headers core trait", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/headers-core@0.3.0", - "externalReferences": [ - { - "type": "website", - "url": "https://hyper.rs" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/headers" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#headers@0.4.1", - "author": "Sean McArthur ", - "name": "headers", - "version": "0.4.1", - "description": "typed HTTP headers", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/headers@0.4.1", - "externalReferences": [ - { - "type": "website", - "url": "https://hyper.rs" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/headers" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heapify@0.2.0", - "name": "heapify", - "version": "0.2.0", - "description": "Convenience functions to turn slices into max-heaps.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "0049b265b7f201ca9ab25475b22b47fe444060126a51abe00f77d986fc5cc52e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/heapify@0.2.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/ethereal-sheep/heapify" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", - "name": "heck", - "version": "0.5.0", - "description": "heck is a case conversion library.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/heck@0.5.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/withoutboats/heck" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heed-traits@0.20.0", - "author": "Kerollmops ", - "name": "heed-traits", - "version": "0.20.0", - "description": "The traits used inside of the fully typed LMDB wrapper, heed", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "eb3130048d404c57ce5a1ac61a903696e8fcde7e8c2991e9fcfc1f27c3ef74ff" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/heed-traits@0.20.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Kerollmops/heed" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heed-types@0.21.0", - "author": "Kerollmops ", - "name": "heed-types", - "version": "0.21.0", - "description": "The types used with the fully typed LMDB wrapper, heed", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "13c255bdf46e07fb840d120a36dcc81f385140d7191c76a7391672675c01a55d" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/heed-types@0.21.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Kerollmops/heed" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heed@0.22.0", - "author": "Kerollmops ", - "name": "heed", - "version": "0.22.0", - "description": "A fully typed LMDB (mdb.master) wrapper with minimum overhead", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6a56c94661ddfb51aa9cdfbf102cfcc340aa69267f95ebccc4af08d7c530d393" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/heed@0.22.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Kerollmops/heed" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#http-body-util@0.1.3", - "author": "Carl Lerche , Lucio Franco , Sean McArthur ", - "name": "http-body-util", - "version": "0.1.3", - "description": "Combinators and adapters for HTTP request or response bodies. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/http-body-util@0.1.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/http-body-util" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/http-body" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "author": "Carl Lerche , Lucio Franco , Sean McArthur ", - "name": "http-body", - "version": "1.0.1", - "description": "Trait representing an asynchronous, streaming, HTTP request or response body. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/http-body@1.0.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/http-body" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/http-body" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "author": "Alex Crichton , Carl Lerche , Sean McArthur ", - "name": "http", - "version": "1.4.0", - "description": "A set of types for representing HTTP requests and responses. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/http@1.4.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/http" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/http" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#httparse@1.10.1", - "author": "Sean McArthur ", - "name": "httparse", - "version": "1.10.1", - "description": "A tiny, safe, speedy, zero-copy HTTP/1.x parser.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/httparse@1.10.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/httparse" - }, - { - "type": "vcs", - "url": "https://github.com/seanmonstar/httparse" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#httpdate@1.0.3", - "author": "Pyfisch ", - "name": "httpdate", - "version": "1.0.3", - "description": "HTTP date parsing and formatting", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/httpdate@1.0.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/pyfisch/httpdate" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#hyper-rustls@0.27.7", - "name": "hyper-rustls", - "version": "0.27.7", - "description": "Rustls+hyper integration for pure rust HTTPS", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR ISC OR MIT" - } - ], - "purl": "pkg:cargo/hyper-rustls@0.27.7", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/hyper-rustls/" - }, - { - "type": "website", - "url": "https://github.com/rustls/hyper-rustls" - }, - { - "type": "vcs", - "url": "https://github.com/rustls/hyper-rustls" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#hyper-util@0.1.20", - "author": "Sean McArthur ", - "name": "hyper-util", - "version": "0.1.20", - "description": "hyper utilities", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/hyper-util@0.1.20", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/hyper-util" - }, - { - "type": "website", - "url": "https://hyper.rs" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/hyper-util" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "author": "Sean McArthur ", - "name": "hyper", - "version": "1.8.1", - "description": "A protective and efficient HTTP library for all.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/hyper@1.8.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/hyper" - }, - { - "type": "website", - "url": "https://hyper.rs" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/hyper" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#iana-time-zone@0.1.65", - "author": "Andrew Straw , René Kijewski , Ryan Lopopolo ", - "name": "iana-time-zone", - "version": "0.1.65", - "description": "get the IANA time zone for the current system", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/iana-time-zone@0.1.65", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/strawlab/iana-time-zone" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_collections@2.1.1", - "author": "The ICU4X Project Developers", - "name": "icu_collections", - "version": "2.1.1", - "description": "Collection of API for use in ICU libraries.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/icu_collections@2.1.1", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locale_core@2.1.1", - "author": "The ICU4X Project Developers", - "name": "icu_locale_core", - "version": "2.1.1", - "description": "API for managing Unicode Language and Locale Identifiers", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/icu_locale_core@2.1.1", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer@2.1.1", - "author": "The ICU4X Project Developers", - "name": "icu_normalizer", - "version": "2.1.1", - "description": "API for normalizing text into Unicode Normalization Forms", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/icu_normalizer@2.1.1", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer_data@2.1.1", - "author": "The ICU4X Project Developers", - "name": "icu_normalizer_data", - "version": "2.1.1", - "description": "Data for the icu_normalizer crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/icu_normalizer_data@2.1.1", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties@2.1.2", - "author": "The ICU4X Project Developers", - "name": "icu_properties", - "version": "2.1.2", - "description": "Definitions for Unicode properties", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/icu_properties@2.1.2", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties_data@2.1.2", - "author": "The ICU4X Project Developers", - "name": "icu_properties_data", - "version": "2.1.2", - "description": "Data for the icu_properties crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/icu_properties_data@2.1.2", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_provider@2.1.1", - "author": "The ICU4X Project Developers", - "name": "icu_provider", - "version": "2.1.1", - "description": "Trait and struct definitions for the ICU data provider", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/icu_provider@2.1.1", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#idna@1.1.0", - "author": "The rust-url developers", - "name": "idna", - "version": "1.1.0", - "description": "IDNA (Internationalizing Domain Names in Applications) and Punycode.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/idna@1.1.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/servo/rust-url/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#idna_adapter@1.2.1", - "author": "The rust-url developers", - "name": "idna_adapter", - "version": "1.2.1", - "description": "Back end adapter for idna", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/idna_adapter@1.2.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/idna_adapter/latest/idna_adapter/" - }, - { - "type": "website", - "url": "https://docs.rs/crate/idna_adapter/latest" - }, - { - "type": "vcs", - "url": "https://github.com/hsivonen/idna_adapter" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#indexmap@2.13.0", - "name": "indexmap", - "version": "2.13.0", - "description": "A hash table with consistent order and fast iteration.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/indexmap@2.13.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/indexmap/" - }, - { - "type": "vcs", - "url": "https://github.com/indexmap-rs/indexmap" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#indoc@2.0.7", - "author": "David Tolnay ", - "name": "indoc", - "version": "2.0.7", - "description": "Indented document literals", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/indoc@2.0.7", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/indoc" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/indoc" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ipnet@2.11.0", - "author": "Kris Price ", - "name": "ipnet", - "version": "2.11.0", - "description": "Provides types and useful methods for working with IPv4 and IPv6 network addresses, commonly called IP prefixes. The new `IpNet`, `Ipv4Net`, and `Ipv6Net` types build on the existing `IpAddr`, `Ipv4Addr`, and `Ipv6Addr` types already provided in Rust's standard library and align to their design to stay consistent. The module also provides useful traits that extend `Ipv4Addr` and `Ipv6Addr` with methods for `Add`, `Sub`, `BitAnd`, and `BitOr` operations. The module only uses stable feature so it is guaranteed to compile using the stable toolchain.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/ipnet@2.11.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/ipnet" - }, - { - "type": "vcs", - "url": "https://github.com/krisprice/ipnet" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#iri-string@0.7.10", - "author": "YOSHIOKA Takuma ", - "name": "iri-string", - "version": "0.7.10", - "description": "IRI as string types", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/iri-string@0.7.10", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/lo48576/iri-string" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#is_terminal_polyfill@1.70.2", - "name": "is_terminal_polyfill", - "version": "1.70.2", - "description": "Polyfill for `is_terminal` stdlib feature for use with older MSRVs", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/is_terminal_polyfill@1.70.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/polyfill-rs/is_terminal_polyfill" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#itertools@0.14.0", - "author": "bluss", - "name": "itertools", - "version": "0.14.0", - "description": "Extra iterator adaptors, iterator methods, free functions, and macros.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/itertools@0.14.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/itertools/" - }, - { - "type": "vcs", - "url": "https://github.com/rust-itertools/itertools" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "author": "David Tolnay ", - "name": "itoa", - "version": "1.0.17", - "description": "Fast integer primitive to string conversion", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/itoa@1.0.17", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/itoa" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/itoa" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#jobserver@0.1.34", - "author": "Alex Crichton ", - "name": "jobserver", - "version": "0.1.34", - "description": "An implementation of the GNU Make jobserver for Rust. ", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/jobserver@0.1.34", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/jobserver" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/jobserver-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/jobserver-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#konst@0.4.3", - "author": "rodrimati1992 ", - "name": "konst", - "version": "0.4.3", - "description": "Const equivalents of std features: comparison, destructuring, iteration, and parsing", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f660d5f887e3562f9ab6f4a14988795b694099d66b4f5dedc02d197ba9becb1d" - } - ], - "licenses": [ - { - "expression": "Zlib" - } - ], - "purl": "pkg:cargo/konst@0.4.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/konst/" - }, - { - "type": "vcs", - "url": "https://github.com/rodrimati1992/konst/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#konst_proc_macros@0.4.1", - "author": "rodrimati1992 ", - "name": "konst_proc_macros", - "version": "0.4.1", - "description": "Implementation detail of the `konst` crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e037a2e1d8d5fdbd49b16a4ea09d5d6401c1f29eca5ff29d03d3824dba16256a" - } - ], - "licenses": [ - { - "expression": "Zlib" - } - ], - "purl": "pkg:cargo/konst_proc_macros@0.4.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/konst/" - }, - { - "type": "vcs", - "url": "https://github.com/rodrimati1992/konst/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "author": "Marvin Löbel ", - "name": "lazy_static", - "version": "1.5.0", - "description": "A macro for declaring lazily evaluated statics in Rust.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/lazy_static@1.5.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/lazy_static" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang-nursery/lazy-static.rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "author": "The Rust Project Developers", - "name": "libc", - "version": "0.2.181", - "description": "Raw FFI bindings to platform libraries like libc.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/libc@0.2.181", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-lang/libc" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#libm@0.2.16", - "author": "Alex Crichton , Amanieu d'Antras , Jorge Aparicio , Trevor Gross ", - "name": "libm", - "version": "0.2.16", - "description": "libm in pure Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/libm@0.2.16", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-lang/compiler-builtins" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#linux-raw-sys@0.11.0", - "author": "Dan Gohman ", - "name": "linux-raw-sys", - "version": "0.11.0", - "description": "Generated bindings for Linux's userspace API", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/linux-raw-sys@0.11.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/linux-raw-sys" - }, - { - "type": "vcs", - "url": "https://github.com/sunfishcode/linux-raw-sys" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#litemap@0.8.1", - "author": "The ICU4X Project Developers", - "name": "litemap", - "version": "0.8.1", - "description": "A key-value Map implementation based on a flat, sorted Vec.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/litemap@0.8.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/litemap" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lmdb-master-sys@0.2.5", - "author": "Kerollmops , Dan Burkert , Victor Porof ", - "name": "lmdb-master-sys", - "version": "0.2.5", - "description": "Rust bindings for liblmdb on the mdb.master branch.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "864808e0b19fb6dd3b70ba94ee671b82fce17554cf80aeb0a155c65bb08027df" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/lmdb-master-sys@0.2.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/lmdb-master-sys" - }, - { - "type": "vcs", - "url": "https://github.com/meilisearch/heed/tree/main/lmdb-master-sys" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lock_api@0.4.14", - "author": "Amanieu d'Antras ", - "name": "lock_api", - "version": "0.4.14", - "description": "Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/lock_api@0.4.14", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Amanieu/parking_lot" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#log@0.4.29", - "author": "The Rust Project Developers", - "name": "log", - "version": "0.4.29", - "description": "A lightweight logging facade for Rust ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/log@0.4.29", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/log" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/log" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lru-slab@0.1.2", - "author": "Benjamin Saunders ", - "name": "lru-slab", - "version": "0.1.2", - "description": "Pre-allocated storage with constant-time LRU tracking", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0 OR Zlib" - } - ], - "purl": "pkg:cargo/lru-slab@0.1.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Ralith/lru-slab" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lz4_flex@0.12.0", - "author": "Pascal Seitz , Arthur Silva , ticki ", - "name": "lz4_flex", - "version": "0.12.0", - "description": "Fastest LZ4 implementation in Rust, no unsafe by default.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/lz4_flex@0.12.0", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pseitz/lz4_flex" - }, - { - "type": "vcs", - "url": "https://github.com/pseitz/lz4_flex" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#matchers@0.2.0", - "author": "Eliza Weisman ", - "name": "matchers", - "version": "0.2.0", - "description": "Regex matching on character and byte streams. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/matchers@0.2.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/matchers/" - }, - { - "type": "website", - "url": "https://github.com/hawkw/matchers" - }, - { - "type": "vcs", - "url": "https://github.com/hawkw/matchers" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#matchit@0.8.4", - "author": "Ibraheem Ahmed ", - "name": "matchit", - "version": "0.8.4", - "description": "A high performance, zero-copy URL router.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - } - ], - "licenses": [ - { - "expression": "MIT AND BSD-3-Clause" - } - ], - "purl": "pkg:cargo/matchit@0.8.4", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/ibraheemdev/matchit" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#matrixmultiply@0.3.10", - "author": "bluss, R. Janis Goldschmidt", - "name": "matrixmultiply", - "version": "0.3.10", - "description": "General matrix multiplication for f32 and f64 matrices. Operates on matrices with general layout (they can use arbitrary row and column stride). Detects and uses AVX or SSE2 on x86 platforms transparently for higher performance. Uses a microkernel strategy, so that the implementation is easy to parallelize and optimize. Supports multithreading.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/matrixmultiply@0.3.10", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/matrixmultiply/" - }, - { - "type": "vcs", - "url": "https://github.com/bluss/matrixmultiply/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "author": "Andrew Gallant , bluss", - "name": "memchr", - "version": "2.8.0", - "description": "Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for 1, 2 or 3 byte search and single substring search. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT" - } - ], - "purl": "pkg:cargo/memchr@2.8.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/memchr/" - }, - { - "type": "website", - "url": "https://github.com/BurntSushi/memchr" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/memchr" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#memoffset@0.9.1", - "author": "Gilad Naaman ", - "name": "memoffset", - "version": "0.9.1", - "description": "offset_of functionality for Rust structs.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/memoffset@0.9.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Gilnaa/memoffset" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17", - "author": "Sean McArthur ", - "name": "mime", - "version": "0.3.17", - "description": "Strongly Typed Mimes", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/mime@0.3.17", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/mime" - }, - { - "type": "vcs", - "url": "https://github.com/hyperium/mime" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#mime_guess@2.0.5", - "author": "Austin Bonander ", - "name": "mime_guess", - "version": "2.0.5", - "description": "A simple crate for detection of a file's MIME type by its extension.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/mime_guess@2.0.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/mime_guess/" - }, - { - "type": "vcs", - "url": "https://github.com/abonander/mime_guess" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#mio@1.1.1", - "author": "Carl Lerche , Thomas de Zeeuw , Tokio Contributors ", - "name": "mio", - "version": "1.1.1", - "description": "Lightweight non-blocking I/O.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/mio@1.1.1", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/tokio-rs/mio" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/mio" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "author": "Thom Chiovoloni ", - "name": "more-asserts", - "version": "0.3.1", - "description": "Small library providing additional assert_* and debug_assert_* macros.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT OR Apache-2.0 OR CC0-1.0" - } - ], - "purl": "pkg:cargo/more-asserts@0.3.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/more-asserts" - }, - { - "type": "website", - "url": "https://github.com/thomcc/rust-more-asserts" - }, - { - "type": "vcs", - "url": "https://github.com/thomcc/rust-more-asserts" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#nalgebra@0.33.2", - "author": "Sébastien Crozet ", - "name": "nalgebra", - "version": "0.33.2", - "description": "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/nalgebra@0.33.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://www.nalgebra.org/docs" - }, - { - "type": "website", - "url": "https://nalgebra.org" - }, - { - "type": "vcs", - "url": "https://github.com/dimforge/nalgebra" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#nu-ansi-term@0.50.3", - "author": "ogham@bsago.me, Ryan Scheel (Havvy) , Josh Triplett , The Nushell Project Developers", - "name": "nu-ansi-term", - "version": "0.50.3", - "description": "Library for ANSI terminal colors and styles (bold, underline)", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/nu-ansi-term@0.50.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/nushell/nu-ansi-term" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", - "author": "The Rust Project Developers", - "name": "num-bigint", - "version": "0.4.6", - "description": "Big integer implementation for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/num-bigint@0.4.6", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/num-bigint" - }, - { - "type": "website", - "url": "https://github.com/rust-num/num-bigint" - }, - { - "type": "vcs", - "url": "https://github.com/rust-num/num-bigint" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-complex@0.4.6", - "author": "The Rust Project Developers", - "name": "num-complex", - "version": "0.4.6", - "description": "Complex numbers implementation for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/num-complex@0.4.6", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/num-complex" - }, - { - "type": "website", - "url": "https://github.com/rust-num/num-complex" - }, - { - "type": "vcs", - "url": "https://github.com/rust-num/num-complex" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-conv@0.2.0", - "author": "Jacob Pratt ", - "name": "num-conv", - "version": "0.2.0", - "description": "`num_conv` is a crate to convert between integer types without using `as` casts. This provides better certainty when refactoring, makes the exact behavior of code more explicit, and allows using turbofish syntax. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/num-conv@0.2.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/jhpratt/num-conv" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.46", - "author": "The Rust Project Developers", - "name": "num-integer", - "version": "0.1.46", - "description": "Integer traits and functions", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/num-integer@0.1.46", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/num-integer" - }, - { - "type": "website", - "url": "https://github.com/rust-num/num-integer" - }, - { - "type": "vcs", - "url": "https://github.com/rust-num/num-integer" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-rational@0.4.2", - "author": "The Rust Project Developers", - "name": "num-rational", - "version": "0.4.2", - "description": "Rational numbers implementation for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/num-rational@0.4.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/num-rational" - }, - { - "type": "website", - "url": "https://github.com/rust-num/num-rational" - }, - { - "type": "vcs", - "url": "https://github.com/rust-num/num-rational" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", - "author": "The Rust Project Developers", - "name": "num-traits", - "version": "0.2.19", - "description": "Numeric traits for generic mathematics", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/num-traits@0.2.19", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/num-traits" - }, - { - "type": "website", - "url": "https://github.com/rust-num/num-traits" - }, - { - "type": "vcs", - "url": "https://github.com/rust-num/num-traits" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "author": "Aleksey Kladov ", - "name": "once_cell", - "version": "1.21.3", - "description": "Single assignment cells and lazy values.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/once_cell@1.21.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/once_cell" - }, - { - "type": "vcs", - "url": "https://github.com/matklad/once_cell" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#oneshot@0.1.13", - "author": "Linus Färnstrand ", - "name": "oneshot", - "version": "0.1.13", - "description": "Oneshot spsc channel with (potentially) lock-free non-blocking send, and a receiver supporting both thread blocking receive operations as well as Future based async polling. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/oneshot@0.1.13", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/faern/oneshot" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-probe@0.2.1", - "author": "Alex Crichton ", - "name": "openssl-probe", - "version": "0.2.1", - "description": "A library for helping to find system-wide trust anchor (\"root\") certificate locations based on paths typically used by `openssl`. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/openssl-probe@0.2.1", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/rustls/openssl-probe" - }, - { - "type": "vcs", - "url": "https://github.com/rustls/openssl-probe" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#option-ext@0.2.0", - "author": "Simon Ochsenreither ", - "name": "option-ext", - "version": "0.2.0", - "description": "Extends `Option` with additional operations", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - } - ], - "licenses": [ - { - "expression": "MPL-2.0" - } - ], - "purl": "pkg:cargo/option-ext@0.2.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/option-ext/" - }, - { - "type": "website", - "url": "https://github.com/soc/option-ext" - }, - { - "type": "vcs", - "url": "https://github.com/soc/option-ext.git" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#os_str_bytes@6.6.1", - "author": "dylni", - "name": "os_str_bytes", - "version": "6.6.1", - "description": "Convert between byte sequences and platform-native strings ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/os_str_bytes@6.6.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/dylni/os_str_bytes" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#page_size@0.6.0", - "author": "Philip Woods ", - "name": "page_size", - "version": "0.6.0", - "description": "Provides an easy, fast, cross-platform way to retrieve the memory page size", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/page_size@0.6.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/page_size/" - }, - { - "type": "website", - "url": "https://github.com/Elzair/page_size_rs" - }, - { - "type": "vcs", - "url": "https://github.com/Elzair/page_size_rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#parking_lot@0.12.5", - "author": "Amanieu d'Antras ", - "name": "parking_lot", - "version": "0.12.5", - "description": "More compact and efficient implementations of the standard synchronization primitives.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/parking_lot@0.12.5", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Amanieu/parking_lot" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#parking_lot_core@0.9.12", - "author": "Amanieu d'Antras ", - "name": "parking_lot_core", - "version": "0.9.12", - "description": "An advanced API for creating custom synchronization primitives.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/parking_lot_core@0.9.12", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Amanieu/parking_lot" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#paste@1.0.15", - "author": "David Tolnay ", - "name": "paste", - "version": "1.0.15", - "description": "Macros for all your token pasting needs", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/paste@1.0.15", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/paste" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/paste" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", - "author": "The rust-url developers", - "name": "percent-encoding", - "version": "2.3.2", - "description": "Percent encoding and decoding", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/percent-encoding@2.3.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/servo/rust-url/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#phf@0.11.3", - "author": "Steven Fackler ", - "name": "phf", - "version": "0.11.3", - "description": "Runtime support for perfect hash function data structures", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/phf@0.11.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-phf/rust-phf" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#phf_generator@0.11.3", - "author": "Steven Fackler ", - "name": "phf_generator", - "version": "0.11.3", - "description": "PHF generation logic", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/phf_generator@0.11.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-phf/rust-phf" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#phf_macros@0.11.3", - "author": "Steven Fackler ", - "name": "phf_macros", - "version": "0.11.3", - "description": "Macros to generate types in the phf crate", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/phf_macros@0.11.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-phf/rust-phf" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#phf_shared@0.11.3", - "author": "Steven Fackler ", - "name": "phf_shared", - "version": "0.11.3", - "description": "Support code shared by PHF libraries", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/phf_shared@0.11.3", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-phf/rust-phf" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pin-project-internal@1.1.10", - "name": "pin-project-internal", - "version": "1.1.10", - "description": "Implementation detail of the `pin-project` crate. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/pin-project-internal@1.1.10", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/taiki-e/pin-project" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "name": "pin-project-lite", - "version": "0.2.16", - "description": "A lightweight version of pin-project written with declarative macros. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/pin-project-lite@0.2.16", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/taiki-e/pin-project-lite" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pin-project@1.1.10", - "name": "pin-project", - "version": "1.1.10", - "description": "A crate for safe and ergonomic pin-projection. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/pin-project@1.1.10", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/taiki-e/pin-project" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pin-utils@0.1.0", - "author": "Josef Brandl ", - "name": "pin-utils", - "version": "0.1.0", - "description": "Utilities for pinning ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pin-utils@0.1.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/pin-utils" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang-nursery/pin-utils" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#potential_utf@0.1.4", - "author": "The ICU4X Project Developers", - "name": "potential_utf", - "version": "0.1.4", - "description": "Unvalidated string and character types", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/potential_utf@0.1.4", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#powerfmt@0.2.0", - "author": "Jacob Pratt ", - "name": "powerfmt", - "version": "0.2.0", - "description": " `powerfmt` is a library that provides utilities for formatting values. This crate makes it significantly easier to support filling to a minimum width with alignment, avoid heap allocation, and avoid repetitive calculations. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/powerfmt@0.2.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/jhpratt/powerfmt" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ppv-lite86@0.2.21", - "author": "The CryptoCorrosion Contributors", - "name": "ppv-lite86", - "version": "0.2.21", - "description": "Cross-platform cryptography-oriented low-level SIMD library.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/ppv-lite86@0.2.21", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/cryptocorrosion/cryptocorrosion" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "author": "David Tolnay , Alex Crichton ", - "name": "proc-macro2", - "version": "1.0.106", - "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/proc-macro2@1.0.106", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/proc-macro2" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/proc-macro2" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#prometheus@0.14.0", - "author": "overvenus@gmail.com, siddontang@gmail.com, vistaswx@gmail.com", - "name": "prometheus", - "version": "0.14.0", - "description": "Prometheus instrumentation library for Rust applications.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/prometheus@0.14.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/prometheus" - }, - { - "type": "website", - "url": "https://github.com/tikv/rust-prometheus" - }, - { - "type": "vcs", - "url": "https://github.com/tikv/rust-prometheus" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#protobuf-support@3.7.2", - "author": "Stepan Koltsov ", - "name": "protobuf-support", - "version": "3.7.2", - "description": "Code supporting protobuf implementation. None of code in this crate is public API. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/protobuf-support@3.7.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://github.com/stepancheg/rust-protobuf/blob/master/README.md" - }, - { - "type": "website", - "url": "https://github.com/stepancheg/rust-protobuf/" - }, - { - "type": "vcs", - "url": "https://github.com/stepancheg/rust-protobuf/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#protobuf@3.7.2", - "author": "Stepan Koltsov ", - "name": "protobuf", - "version": "3.7.2", - "description": "Rust implementation of Google protocol buffers ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/protobuf@3.7.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://github.com/stepancheg/rust-protobuf/blob/master/README.md" - }, - { - "type": "website", - "url": "https://github.com/stepancheg/rust-protobuf/" - }, - { - "type": "vcs", - "url": "https://github.com/stepancheg/rust-protobuf/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.26.0", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-build-config", - "version": "0.26.0", - "description": "Build configuration for the PyO3 ecosystem", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-build-config@0.26.0", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.26.0", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-ffi", - "version": "0.26.0", - "description": "Python-API bindings for the PyO3 ecosystem", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-ffi@0.26.0", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "other", - "url": "python" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.26.0", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-macros-backend", - "version": "0.26.0", - "description": "Code generation for PyO3 package", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-macros-backend@0.26.0", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.26.0", - "author": "PyO3 Project and Contributors ", - "name": "pyo3-macros", - "version": "0.26.0", - "description": "Proc macros for PyO3 package", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3-macros@0.26.0", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.26.0", - "author": "PyO3 Project and Contributors ", - "name": "pyo3", - "version": "0.26.0", - "description": "Bindings to Python interpreter", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/pyo3@0.26.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/crate/pyo3/" - }, - { - "type": "website", - "url": "https://github.com/pyo3/pyo3" - }, - { - "type": "vcs", - "url": "https://github.com/pyo3/pyo3" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quinn-proto@0.11.13", - "name": "quinn-proto", - "version": "0.11.13", - "description": "State machine for the QUIC transport protocol", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/quinn-proto@0.11.13", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/quinn-rs/quinn" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quinn-udp@0.5.14", - "name": "quinn-udp", - "version": "0.5.14", - "description": "UDP sockets with ECN information for the QUIC transport protocol", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/quinn-udp@0.5.14", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/quinn-rs/quinn" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quinn@0.11.9", - "name": "quinn", - "version": "0.11.9", - "description": "Versatile QUIC transport protocol implementation", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/quinn@0.11.9", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/quinn-rs/quinn" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "author": "David Tolnay ", - "name": "quote", - "version": "1.0.44", - "description": "Quasi-quoting macro quote!(...)", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/quote@1.0.44", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/quote/" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/quote" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5", - "author": "The Rand Project Developers, The Rust Project Developers", - "name": "rand", - "version": "0.8.5", - "description": "Random number generators and other randomness functionality. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rand@0.8.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rand" - }, - { - "type": "website", - "url": "https://rust-random.github.io/book" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/rand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "author": "The Rand Project Developers, The Rust Project Developers", - "name": "rand", - "version": "0.9.2", - "description": "Random number generators and other randomness functionality. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rand@0.9.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rand" - }, - { - "type": "website", - "url": "https://rust-random.github.io/book" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/rand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.3.1", - "author": "The Rand Project Developers, The Rust Project Developers, The CryptoCorrosion Contributors", - "name": "rand_chacha", - "version": "0.3.1", - "description": "ChaCha random number generator ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rand_chacha@0.3.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rand_chacha" - }, - { - "type": "website", - "url": "https://rust-random.github.io/book" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/rand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.9.0", - "author": "The Rand Project Developers, The Rust Project Developers, The CryptoCorrosion Contributors", - "name": "rand_chacha", - "version": "0.9.0", - "description": "ChaCha random number generator ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rand_chacha@0.9.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rand_chacha" - }, - { - "type": "website", - "url": "https://rust-random.github.io/book" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/rand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.6.4", - "author": "The Rand Project Developers, The Rust Project Developers", - "name": "rand_core", - "version": "0.6.4", - "description": "Core random number generator traits and tools for implementation. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rand_core@0.6.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rand_core" - }, - { - "type": "website", - "url": "https://rust-random.github.io/book" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/rand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.9.5", - "author": "The Rand Project Developers, The Rust Project Developers", - "name": "rand_core", - "version": "0.9.5", - "description": "Core random number generator traits and tools for implementation. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rand_core@0.9.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rand_core" - }, - { - "type": "website", - "url": "https://rust-random.github.io/book" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/rand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rand_distr@0.4.3", - "author": "The Rand Project Developers", - "name": "rand_distr", - "version": "0.4.3", - "description": "Sampling from random number distributions ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rand_distr@0.4.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rand_distr" - }, - { - "type": "website", - "url": "https://rust-random.github.io/book" - }, - { - "type": "vcs", - "url": "https://github.com/rust-random/rand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rawpointer@0.2.1", - "author": "bluss", - "name": "rawpointer", - "version": "0.2.1", - "description": "Extra methods for raw pointers and `NonNull`. For example `.post_inc()` and `.pre_dec()` (c.f. `ptr++` and `--ptr`), `offset` and `add` for `NonNull`, and the function `ptrdistance`. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rawpointer@0.2.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rawpointer/" - }, - { - "type": "vcs", - "url": "https://github.com/bluss/rawpointer/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.14", - "author": "The Rust Project Developers, Andrew Gallant ", - "name": "regex-automata", - "version": "0.4.14", - "description": "Automata construction and matching using regular expressions.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/regex-automata@0.4.14", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/regex-automata" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/regex/tree/master/regex-automata" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/regex" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.9", - "author": "The Rust Project Developers, Andrew Gallant ", - "name": "regex-syntax", - "version": "0.8.9", - "description": "A regular expression parser.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/regex-syntax@0.8.9", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/regex-syntax" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/regex/tree/master/regex-syntax" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/regex" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#regex@1.12.3", - "author": "The Rust Project Developers, Andrew Gallant ", - "name": "regex", - "version": "1.12.3", - "description": "An implementation of regular expressions for Rust. This implementation uses finite automata and guarantees linear time matching on all inputs. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/regex@1.12.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/regex" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/regex" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/regex" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#reqwest-middleware@0.5.1", - "author": "Rodrigo Gryzinski ", - "name": "reqwest-middleware", - "version": "0.5.1", - "description": "Wrapper around reqwest to allow for client middleware chains.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "199dda04a536b532d0cc04d7979e39b1c763ea749bf91507017069c00b96056f" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/reqwest-middleware@0.5.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/TrueLayer/reqwest-middleware" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#reqwest-retry@0.9.1", - "author": "Rodrigo Gryzinski ", - "name": "reqwest-retry", - "version": "0.9.1", - "description": "Retry middleware for reqwest.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "fe2412db2af7d2268e7a5406be0431f37d9eb67ff390f35b395716f5f06c2eaa" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/reqwest-retry@0.9.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/TrueLayer/reqwest-middleware" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#reqwest@0.13.2", - "author": "Sean McArthur ", - "name": "reqwest", - "version": "0.13.2", - "description": "higher level HTTP client library", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/reqwest@0.13.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/reqwest" - }, - { - "type": "vcs", - "url": "https://github.com/seanmonstar/reqwest" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#retry-policies@0.5.1", - "author": "Luca Palmieri ", - "name": "retry-policies", - "version": "0.5.1", - "description": "A collection of plug-and-play retry policies for Rust projects.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "46a4bd6027df676bcb752d3724db0ea3c0c5fc1dd0376fec51ac7dcaf9cc69be" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/retry-policies@0.5.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/TrueLayer/retry-policies" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ring@0.17.14", - "name": "ring", - "version": "0.17.14", - "description": "An experiment.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 AND ISC" - } - ], - "purl": "pkg:cargo/ring@0.17.14", - "externalReferences": [ - { - "type": "other", - "url": "ring_core_0_17_14_" - }, - { - "type": "vcs", - "url": "https://github.com/briansmith/ring" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rust_decimal@1.40.0", - "author": "Paul Mason ", - "name": "rust_decimal", - "version": "1.40.0", - "description": "Decimal number implementation written in pure Rust suitable for financial and fixed-precision calculations.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/rust_decimal@1.40.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rust_decimal/" - }, - { - "type": "vcs", - "url": "https://github.com/paupino/rust-decimal" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustc-hash@2.1.1", - "author": "The Rust Project Developers", - "name": "rustc-hash", - "version": "2.1.1", - "description": "A speedy, non-cryptographic hashing algorithm used by rustc", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/rustc-hash@2.1.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rust-lang/rustc-hash" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustix@1.1.3", - "author": "Dan Gohman , Jakub Konka ", - "name": "rustix", - "version": "1.1.3", - "description": "Safe Rust bindings to POSIX/Unix/Linux/Winsock-like syscalls", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/rustix@1.1.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rustix" - }, - { - "type": "vcs", - "url": "https://github.com/bytecodealliance/rustix" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-native-certs@0.8.3", - "name": "rustls-native-certs", - "version": "0.8.3", - "description": "rustls-native-certs allows rustls to use the platform native certificate store", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR ISC OR MIT" - } - ], - "purl": "pkg:cargo/rustls-native-certs@0.8.3", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/rustls/rustls-native-certs" - }, - { - "type": "vcs", - "url": "https://github.com/rustls/rustls-native-certs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-pki-types@1.14.0", - "name": "rustls-pki-types", - "version": "1.14.0", - "description": "Shared types for the rustls PKI ecosystem", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rustls-pki-types@1.14.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rustls-pki-types" - }, - { - "type": "website", - "url": "https://github.com/rustls/pki-types" - }, - { - "type": "vcs", - "url": "https://github.com/rustls/pki-types" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-platform-verifier@0.6.2", - "name": "rustls-platform-verifier", - "version": "0.6.2", - "description": "rustls-platform-verifier supports verifying TLS certificates in rustls with the operating system verifier", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rustls-platform-verifier@0.6.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rustls/rustls-platform-verifier" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-webpki@0.103.9", - "name": "rustls-webpki", - "version": "0.103.9", - "description": "Web PKI X.509 Certificate Verification.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" - } - ], - "licenses": [ - { - "expression": "ISC" - } - ], - "purl": "pkg:cargo/rustls-webpki@0.103.9", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/rustls/webpki" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "name": "rustls", - "version": "0.23.36", - "description": "Rustls is a modern TLS library written in Rust.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR ISC OR MIT" - } - ], - "purl": "pkg:cargo/rustls@0.23.36", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/rustls/rustls" - }, - { - "type": "vcs", - "url": "https://github.com/rustls/rustls" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustversion@1.0.22", - "author": "David Tolnay ", - "name": "rustversion", - "version": "1.0.22", - "description": "Conditional compilation according to rustc compiler version", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/rustversion@1.0.22", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/rustversion" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/rustversion" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ryu@1.0.23", - "author": "David Tolnay ", - "name": "ryu", - "version": "1.0.23", - "description": "Fast floating point to string conversion", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR BSL-1.0" - } - ], - "purl": "pkg:cargo/ryu@1.0.23", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/ryu" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/ryu" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#safe-transmute@0.11.3", - "author": "наб , Eduardo Pinho , Lukas Kalbertodt , Philipp Tessenow , Marijn Suijten ", - "name": "safe-transmute", - "version": "0.11.3", - "description": "A safeguarded transmute() for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3944826ff8fa8093089aba3acb4ef44b9446a99a16f3bf4e74af3f77d340ab7d" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/safe-transmute@0.11.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://rawcdn.githack.com/nabijaczleweli/safe-transmute-rs/doc/safe_transmute/index.html" - }, - { - "type": "vcs", - "url": "https://github.com/nabijaczleweli/safe-transmute-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#safe_arch@0.7.4", - "author": "Lokathor ", - "name": "safe_arch", - "version": "0.7.4", - "description": "Crate that exposes `core::arch` safely via `#[cfg()]`.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" - } - ], - "licenses": [ - { - "expression": "Zlib OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/safe_arch@0.7.4", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Lokathor/safe_arch" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#same-file@1.0.6", - "author": "Andrew Gallant ", - "name": "same-file", - "version": "1.0.6", - "description": "A simple crate for determining whether two file paths point to the same file. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT" - } - ], - "purl": "pkg:cargo/same-file@1.0.6", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/same-file" - }, - { - "type": "website", - "url": "https://github.com/BurntSushi/same-file" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/same-file" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#scoped-tls@1.0.1", - "author": "Alex Crichton ", - "name": "scoped-tls", - "version": "1.0.1", - "description": "Library implementation of the standard library's old `scoped_thread_local!` macro for providing scoped access to thread local storage (TLS) so any type can be stored into TLS. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/scoped-tls@1.0.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/scoped-tls" - }, - { - "type": "website", - "url": "https://github.com/alexcrichton/scoped-tls" - }, - { - "type": "vcs", - "url": "https://github.com/alexcrichton/scoped-tls" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#scopeguard@1.2.0", - "author": "bluss", - "name": "scopeguard", - "version": "1.2.0", - "description": "A RAII scope guard that will run a given closure when it goes out of scope, even if the code between panics (assuming unwinding panic). Defines the macros `defer!`, `defer_on_unwind!`, `defer_on_success!` as shorthands for guards with one of the implemented strategies. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/scopeguard@1.2.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/scopeguard/" - }, - { - "type": "vcs", - "url": "https://github.com/bluss/scopeguard" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "author": "Erick Tryzelaar , David Tolnay ", - "name": "serde", - "version": "1.0.228", - "description": "A generic serialization/deserialization framework", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/serde@1.0.228", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/serde" - }, - { - "type": "website", - "url": "https://serde.rs" - }, - { - "type": "vcs", - "url": "https://github.com/serde-rs/serde" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", - "author": "Erick Tryzelaar , David Tolnay ", - "name": "serde_core", - "version": "1.0.228", - "description": "Serde traits only, with no support for derive -- use the `serde` crate instead", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/serde_core@1.0.228", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/serde_core" - }, - { - "type": "website", - "url": "https://serde.rs" - }, - { - "type": "vcs", - "url": "https://github.com/serde-rs/serde" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228", - "author": "Erick Tryzelaar , David Tolnay ", - "name": "serde_derive", - "version": "1.0.228", - "description": "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/serde_derive@1.0.228", - "externalReferences": [ - { - "type": "documentation", - "url": "https://serde.rs/derive.html" - }, - { - "type": "website", - "url": "https://serde.rs" - }, - { - "type": "vcs", - "url": "https://github.com/serde-rs/serde" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "author": "Erick Tryzelaar , David Tolnay ", - "name": "serde_json", - "version": "1.0.149", - "description": "A JSON serialization file format", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/serde_json@1.0.149", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/serde_json" - }, - { - "type": "vcs", - "url": "https://github.com/serde-rs/json" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_path_to_error@0.1.20", - "author": "David Tolnay ", - "name": "serde_path_to_error", - "version": "0.1.20", - "description": "Path to the element that failed to deserialize", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/serde_path_to_error@0.1.20", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/serde_path_to_error" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/path-to-error" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_repr@0.1.20", - "author": "David Tolnay ", - "name": "serde_repr", - "version": "0.1.20", - "description": "Derive Serialize and Deserialize that delegates to the underlying repr of a C-like enum.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/serde_repr@0.1.20", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/serde_repr" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/serde-repr" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_urlencoded@0.7.1", - "author": "Anthony Ramine ", - "name": "serde_urlencoded", - "version": "0.7.1", - "description": "`x-www-form-urlencoded` meets Serde", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/serde_urlencoded@0.7.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/serde_urlencoded/0.7.1/serde_urlencoded/" - }, - { - "type": "vcs", - "url": "https://github.com/nox/serde_urlencoded" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#sha1@0.10.6", - "author": "RustCrypto Developers", - "name": "sha1", - "version": "0.10.6", - "description": "SHA-1 hash function", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/sha1@0.10.6", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/sha1" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/hashes" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#sha2-asm@0.6.4", - "author": "RustCrypto Developers", - "name": "sha2-asm", - "version": "0.6.4", - "description": "Assembly implementation of SHA-2 compression functions", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/sha2-asm@0.6.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/sha2-asm" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/asm-hashes" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#sha2@0.10.9", - "author": "RustCrypto Developers", - "name": "sha2", - "version": "0.10.9", - "description": "Pure Rust implementation of the SHA-2 hash function family including SHA-224, SHA-256, SHA-384, and SHA-512. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/sha2@0.10.9", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/sha2" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/hashes" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#sharded-slab@0.1.7", - "author": "Eliza Weisman ", - "name": "sharded-slab", - "version": "0.1.7", - "description": "A lock-free concurrent slab. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/sharded-slab@0.1.7", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/sharded-slab/" - }, - { - "type": "website", - "url": "https://github.com/hawkw/sharded-slab" - }, - { - "type": "vcs", - "url": "https://github.com/hawkw/sharded-slab" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#shellexpand@3.1.1", - "author": "Vladimir Matveev , Ian Jackson ", - "name": "shellexpand", - "version": "3.1.1", - "description": "Shell-like expansions in strings", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/shellexpand@3.1.1", - "externalReferences": [ - { - "type": "documentation", - "url": "http://docs.rs/shellexpand/" - }, - { - "type": "vcs", - "url": "https://gitlab.com/ijackson/rust-shellexpand" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@1.3.0", - "author": "comex , Fenhl , Adrian Taylor , Alex Touchet , Daniel Parks , Garrett Berg ", - "name": "shlex", - "version": "1.3.0", - "description": "Split a string into shell words, like Python's shlex.", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/shlex@1.3.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/comex/rust-shlex" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#signal-hook-registry@1.4.8", - "author": "Michal 'vorner' Vaner , Masaki Hara ", - "name": "signal-hook-registry", - "version": "1.4.8", - "description": "Backend crate for signal-hook", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/signal-hook-registry@1.4.8", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/signal-hook-registry" - }, - { - "type": "vcs", - "url": "https://github.com/vorner/signal-hook" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#signal-hook@0.3.18", - "author": "Michal 'vorner' Vaner , Thomas Himmelstoss ", - "name": "signal-hook", - "version": "0.3.18", - "description": "Unix signal handling", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/signal-hook@0.3.18", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/signal-hook" - }, - { - "type": "vcs", - "url": "https://github.com/vorner/signal-hook" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#simba@0.9.1", - "author": "sebcrozet ", - "name": "simba", - "version": "0.9.1", - "description": "SIMD algebra for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "c99284beb21666094ba2b75bbceda012e610f5479dfcc2d6e2426f53197ffd95" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/simba@0.9.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/simba" - }, - { - "type": "vcs", - "url": "https://github.com/dimforge/simba" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#siphasher@1.0.2", - "author": "Frank Denis ", - "name": "siphasher", - "version": "1.0.2", - "description": "SipHash-2-4, SipHash-1-3 and 128-bit variants in pure Rust", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/siphasher@1.0.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/siphasher" - }, - { - "type": "website", - "url": "https://docs.rs/siphasher" - }, - { - "type": "vcs", - "url": "https://github.com/jedisct1/rust-siphash" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#slab@0.4.12", - "author": "Carl Lerche ", - "name": "slab", - "version": "0.4.12", - "description": "Pre-allocated storage for a uniform data type", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/slab@0.4.12", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/tokio-rs/slab" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", - "author": "The Servo Project Developers", - "name": "smallvec", - "version": "1.15.1", - "description": "'Small vector' optimization: store up to a small number of items on the stack", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/smallvec@1.15.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/smallvec/" - }, - { - "type": "vcs", - "url": "https://github.com/servo/rust-smallvec" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#socket2@0.6.2", - "author": "Alex Crichton , Thomas de Zeeuw ", - "name": "socket2", - "version": "0.6.2", - "description": "Utilities for handling networking sockets with a maximal amount of configuration possible intended. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/socket2@0.6.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/socket2" - }, - { - "type": "website", - "url": "https://github.com/rust-lang/socket2" - }, - { - "type": "vcs", - "url": "https://github.com/rust-lang/socket2" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#stable_deref_trait@1.2.1", - "author": "Robert Grosse ", - "name": "stable_deref_trait", - "version": "1.2.1", - "description": "An unsafe marker trait for types like Box and Rc that dereference to a stable address even when moved, and hence can be used with libraries such as owning_ref and rental. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/stable_deref_trait@1.2.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/stable_deref_trait/1.2.1/stable_deref_trait" - }, - { - "type": "vcs", - "url": "https://github.com/storyyeller/stable_deref_trait" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0", - "author": "Nikolai Vazquez", - "name": "static_assertions", - "version": "1.1.0", - "description": "Compile-time assertions to ensure that invariants are met.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/static_assertions@1.1.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/static_assertions/" - }, - { - "type": "website", - "url": "https://github.com/nvzqz/static-assertions-rs" - }, - { - "type": "vcs", - "url": "https://github.com/nvzqz/static-assertions-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#statrs@0.18.0", - "author": "Michael Ma", - "name": "statrs", - "version": "0.18.0", - "description": "Statistical computing library for Rust", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2a3fe7c28c6512e766b0874335db33c94ad7b8f9054228ae1c2abd47ce7d335e" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/statrs@0.18.0", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/statrs-dev/statrs" - }, - { - "type": "vcs", - "url": "https://github.com/statrs-dev/statrs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#strsim@0.11.1", - "author": "Danny Guo , maxbachmann ", - "name": "strsim", - "version": "0.11.1", - "description": "Implementations of string similarity metrics. Includes Hamming, Levenshtein, OSA, Damerau-Levenshtein, Jaro, Jaro-Winkler, and Sørensen-Dice. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/strsim@0.11.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/strsim/" - }, - { - "type": "website", - "url": "https://github.com/rapidfuzz/strsim-rs" - }, - { - "type": "vcs", - "url": "https://github.com/rapidfuzz/strsim-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#subtle@2.6.1", - "author": "Isis Lovecruft , Henry de Valence ", - "name": "subtle", - "version": "2.6.1", - "description": "Pure-Rust traits and utilities for constant-time cryptographic implementations.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - } - ], - "licenses": [ - { - "expression": "BSD-3-Clause" - } - ], - "purl": "pkg:cargo/subtle@2.6.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/subtle" - }, - { - "type": "website", - "url": "https://dalek.rs/" - }, - { - "type": "vcs", - "url": "https://github.com/dalek-cryptography/subtle" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#syn@1.0.109", - "author": "David Tolnay ", - "name": "syn", - "version": "1.0.109", - "description": "Parser for Rust source code", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/syn@1.0.109", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/syn" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/syn" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114", - "author": "David Tolnay ", - "name": "syn", - "version": "2.0.114", - "description": "Parser for Rust source code", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/syn@2.0.114", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/syn" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/syn" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#sync_wrapper@1.0.2", - "author": "Actyx AG ", - "name": "sync_wrapper", - "version": "1.0.2", - "description": "A tool for enlisting the compiler's help in proving the absence of concurrency", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" - } - ], - "licenses": [ - { - "expression": "Apache-2.0" - } - ], - "purl": "pkg:cargo/sync_wrapper@1.0.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/sync_wrapper" - }, - { - "type": "website", - "url": "https://docs.rs/sync_wrapper" - }, - { - "type": "vcs", - "url": "https://github.com/Actyx/sync_wrapper" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#synchronoise@1.0.1", - "author": "QuietMisdreavus ", - "name": "synchronoise", - "version": "1.0.1", - "description": "Synchronization primitives that build upon the standard library", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "3dbc01390fc626ce8d1cffe3376ded2b72a11bb70e1c75f404a210e4daa4def2" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/synchronoise@1.0.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/synchronoise/" - }, - { - "type": "vcs", - "url": "https://github.com/QuietMisdreavus/synchronoise" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.2", - "author": "Nika Layzell ", - "name": "synstructure", - "version": "0.13.2", - "description": "Helper methods and macros for custom derives", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/synstructure@0.13.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/synstructure" - }, - { - "type": "vcs", - "url": "https://github.com/mystor/synstructure" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#sysinfo@0.38.1", - "author": "Guillaume Gomez ", - "name": "sysinfo", - "version": "0.38.1", - "description": "Library to get system information such as processes, CPUs, disks, components and networks", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "5792d209c2eac902426c0c4a166c9f72147db453af548cf9bf3242644c4d4fe3" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/sysinfo@0.38.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/GuillaumeGomez/sysinfo" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.4", - "author": "Dan Gohman ", - "name": "target-lexicon", - "version": "0.13.4", - "description": "LLVM target triple types", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 WITH LLVM-exception" - } - ], - "purl": "pkg:cargo/target-lexicon@0.13.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/target-lexicon/" - }, - { - "type": "vcs", - "url": "https://github.com/bytecodealliance/target-lexicon" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tempfile@3.25.0", - "author": "Steven Allen , The Rust Project Developers, Ashley Mannix , Jason White ", - "name": "tempfile", - "version": "3.25.0", - "description": "A library for managing temporary files and directories.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/tempfile@3.25.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/tempfile" - }, - { - "type": "website", - "url": "https://stebalien.com/projects/tempfile-rs/" - }, - { - "type": "vcs", - "url": "https://github.com/Stebalien/tempfile" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror-impl@1.0.69", - "author": "David Tolnay ", - "name": "thiserror-impl", - "version": "1.0.69", - "description": "Implementation detail of the `thiserror` crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/thiserror-impl@1.0.69", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/dtolnay/thiserror" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror-impl@2.0.18", - "author": "David Tolnay ", - "name": "thiserror-impl", - "version": "2.0.18", - "description": "Implementation detail of the `thiserror` crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/thiserror-impl@2.0.18", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/dtolnay/thiserror" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror@1.0.69", - "author": "David Tolnay ", - "name": "thiserror", - "version": "1.0.69", - "description": "derive(Error)", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/thiserror@1.0.69", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/thiserror" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/thiserror" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "author": "David Tolnay ", - "name": "thiserror", - "version": "2.0.18", - "description": "derive(Error)", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/thiserror@2.0.18", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/thiserror" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/thiserror" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#thread_local@1.1.9", - "author": "Amanieu d'Antras ", - "name": "thread_local", - "version": "1.1.9", - "description": "Per-object thread-local storage", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/thread_local@1.1.9", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/thread_local/" - }, - { - "type": "vcs", - "url": "https://github.com/Amanieu/thread_local-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#time-core@0.1.8", - "author": "Jacob Pratt , Time contributors", - "name": "time-core", - "version": "0.1.8", - "description": "This crate is an implementation detail and should not be relied upon directly.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/time-core@0.1.8", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/time-rs/time" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#time-macros@0.2.27", - "author": "Jacob Pratt , Time contributors", - "name": "time-macros", - "version": "0.2.27", - "description": " Procedural macros for the time crate. This crate is an implementation detail and should not be relied upon directly. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/time-macros@0.2.27", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/time-rs/time" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#time@0.3.47", - "author": "Jacob Pratt , Time contributors", - "name": "time", - "version": "0.3.47", - "description": "Date and time library. Fully interoperable with the standard library. Mostly compatible with #![no_std].", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/time@0.3.47", - "externalReferences": [ - { - "type": "website", - "url": "https://time-rs.github.io" - }, - { - "type": "vcs", - "url": "https://github.com/time-rs/time" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.8.2", - "author": "The ICU4X Project Developers", - "name": "tinystr", - "version": "0.8.2", - "description": "A small ASCII-only bounded length string representation.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/tinystr@0.8.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tinyvec@1.10.0", - "author": "Lokathor ", - "name": "tinyvec", - "version": "1.10.0", - "description": "`tinyvec` provides 100% safe vec-like data structures.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" - } - ], - "licenses": [ - { - "expression": "Zlib OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/tinyvec@1.10.0", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Lokathor/tinyvec" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tinyvec_macros@0.1.1", - "author": "Soveu ", - "name": "tinyvec_macros", - "version": "0.1.1", - "description": "Some macros for tiny containers", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0 OR Zlib" - } - ], - "purl": "pkg:cargo/tinyvec_macros@0.1.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Soveu/tinyvec_macros" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-macros@2.6.0", - "author": "Tokio Contributors ", - "name": "tokio-macros", - "version": "2.6.0", - "description": "Tokio's proc macros. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tokio-macros@2.6.0", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tokio" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-retry@0.3.0", - "author": "Sam Rijs ", - "name": "tokio-retry", - "version": "0.3.0", - "description": "Extensible, asynchronous retry behaviours for futures/tokio", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tokio-retry@0.3.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/tokio-retry" - }, - { - "type": "vcs", - "url": "https://github.com/srijs/rust-tokio-retry" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-rustls@0.26.4", - "name": "tokio-rustls", - "version": "0.26.4", - "description": "Asynchronous TLS/SSL streams for Tokio using Rustls.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/tokio-rustls@0.26.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/tokio-rustls" - }, - { - "type": "website", - "url": "https://github.com/rustls/tokio-rustls" - }, - { - "type": "vcs", - "url": "https://github.com/rustls/tokio-rustls" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-util@0.7.18", - "author": "Tokio Contributors ", - "name": "tokio-util", - "version": "0.7.18", - "description": "Additional utilities for working with Tokio. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tokio-util@0.7.18", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tokio" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "author": "Tokio Contributors ", - "name": "tokio", - "version": "1.49.0", - "description": "An event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tokio@1.49.0", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tokio" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tower-http@0.6.8", - "author": "Tower Maintainers ", - "name": "tower-http", - "version": "0.6.8", - "description": "Tower middleware and utilities for HTTP clients and servers", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tower-http@0.6.8", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/tower-rs/tower-http" - }, - { - "type": "vcs", - "url": "https://github.com/tower-rs/tower-http" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tower-layer@0.3.3", - "author": "Tower Maintainers ", - "name": "tower-layer", - "version": "0.3.3", - "description": "Decorates a `Service` to allow easy composition between `Service`s. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tower-layer@0.3.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/tower-layer/0.3.3" - }, - { - "type": "website", - "url": "https://github.com/tower-rs/tower" - }, - { - "type": "vcs", - "url": "https://github.com/tower-rs/tower" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "author": "Tower Maintainers ", - "name": "tower-service", - "version": "0.3.3", - "description": "Trait representing an asynchronous, request / response based, client or server. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tower-service@0.3.3", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/tower-service/0.3.3" - }, - { - "type": "website", - "url": "https://github.com/tower-rs/tower" - }, - { - "type": "vcs", - "url": "https://github.com/tower-rs/tower" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tower@0.5.3", - "author": "Tower Maintainers ", - "name": "tower", - "version": "0.5.3", - "description": "Tower is a library of modular and reusable components for building robust clients and servers. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tower@0.5.3", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/tower-rs/tower" - }, - { - "type": "vcs", - "url": "https://github.com/tower-rs/tower" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-appender@0.2.4", - "author": "Zeki Sherif , Tokio Contributors ", - "name": "tracing-appender", - "version": "0.2.4", - "description": "Provides utilities for file appenders and making non-blocking writers. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tracing-appender@0.2.4", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tracing" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-attributes@0.1.31", - "author": "Tokio Contributors , Eliza Weisman , David Barsky ", - "name": "tracing-attributes", - "version": "0.1.31", - "description": "Procedural macro attributes for automatically instrumenting functions. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tracing-attributes@0.1.31", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tracing" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-core@0.1.36", - "author": "Tokio Contributors ", - "name": "tracing-core", - "version": "0.1.36", - "description": "Core primitives for application-level tracing. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tracing-core@0.1.36", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tracing" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-log@0.2.0", - "author": "Tokio Contributors ", - "name": "tracing-log", - "version": "0.2.0", - "description": "Provides compatibility between `tracing` and the `log` crate. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tracing-log@0.2.0", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tracing" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-serde@0.2.0", - "author": "Tokio Contributors ", - "name": "tracing-serde", - "version": "0.2.0", - "description": "A compatibility layer for serializing trace data with `serde` ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tracing-serde@0.2.0", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tracing" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-subscriber@0.3.22", - "author": "Eliza Weisman , David Barsky , Tokio Contributors ", - "name": "tracing-subscriber", - "version": "0.3.22", - "description": "Utilities for implementing and composing `tracing` subscribers. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tracing-subscriber@0.3.22", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tracing" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "author": "Eliza Weisman , Tokio Contributors ", - "name": "tracing", - "version": "0.1.44", - "description": "Application-level tracing for Rust. ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/tracing@0.1.44", - "externalReferences": [ - { - "type": "website", - "url": "https://tokio.rs" - }, - { - "type": "vcs", - "url": "https://github.com/tokio-rs/tracing" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#try-lock@0.2.5", - "author": "Sean McArthur ", - "name": "try-lock", - "version": "0.2.5", - "description": "A lightweight atomic lock.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/try-lock@0.2.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/try-lock" - }, - { - "type": "website", - "url": "https://github.com/seanmonstar/try-lock" - }, - { - "type": "vcs", - "url": "https://github.com/seanmonstar/try-lock" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#twox-hash@2.1.2", - "author": "Jake Goulding ", - "name": "twox-hash", - "version": "2.1.2", - "description": "A Rust implementation of the XXHash and XXH3 algorithms", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/twox-hash@2.1.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/twox-hash/" - }, - { - "type": "vcs", - "url": "https://github.com/shepmaster/twox-hash" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#typenum@1.19.0", - "author": "Paho Lurie-Gregg , Andre Bogus ", - "name": "typenum", - "version": "1.19.0", - "description": "Typenum is a Rust library for type-level numbers evaluated at compile time. It currently supports bits, unsigned integers, and signed integers. It also provides a type-level array of type-level numbers, but its implementation is incomplete.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/typenum@1.19.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/typenum" - }, - { - "type": "vcs", - "url": "https://github.com/paholg/typenum" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#typewit@1.14.2", - "author": "rodrimati1992 ", - "name": "typewit", - "version": "1.14.2", - "description": "type-witness-based abstractions, mostly for emulating polymorphism in const fns", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "f8c1ae7cc0fdb8b842d65d127cb981574b0d2b249b74d1c7a2986863dc134f71" - } - ], - "licenses": [ - { - "expression": "Zlib" - } - ], - "purl": "pkg:cargo/typewit@1.14.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/typewit/" - }, - { - "type": "vcs", - "url": "https://github.com/rodrimati1992/typewit/" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ulid@1.2.1", - "author": "dylanhart ", - "name": "ulid", - "version": "1.2.1", - "description": "a Universally Unique Lexicographically Sortable Identifier implementation", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/ulid@1.2.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/dylanhart/ulid-rs" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unicase@2.9.0", - "author": "Sean McArthur ", - "name": "unicase", - "version": "2.9.0", - "description": "A case-insensitive wrapper around strings.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/unicase@2.9.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/unicase" - }, - { - "type": "vcs", - "url": "https://github.com/seanmonstar/unicase" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.23", - "author": "David Tolnay ", - "name": "unicode-ident", - "version": "1.0.23", - "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" - } - ], - "licenses": [ - { - "expression": "(MIT OR Apache-2.0) AND Unicode-3.0" - } - ], - "purl": "pkg:cargo/unicode-ident@1.0.23", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/unicode-ident" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/unicode-ident" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unindent@0.2.4", - "author": "David Tolnay ", - "name": "unindent", - "version": "0.2.4", - "description": "Remove a column of leading whitespace from a string", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/unindent@0.2.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/unindent" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/indoc" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#untrusted@0.9.0", - "author": "Brian Smith ", - "name": "untrusted", - "version": "0.9.0", - "description": "Safe, fast, zero-panic, zero-crashing, zero-allocation parsing of untrusted inputs in Rust.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - } - ], - "licenses": [ - { - "expression": "ISC" - } - ], - "purl": "pkg:cargo/untrusted@0.9.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://briansmith.org/rustdoc/untrusted/" - }, - { - "type": "vcs", - "url": "https://github.com/briansmith/untrusted" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#url@2.5.8", - "author": "The rust-url developers", - "name": "url", - "version": "2.5.8", - "description": "URL library for Rust, based on the WHATWG URL Standard", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/url@2.5.8", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/url" - }, - { - "type": "vcs", - "url": "https://github.com/servo/rust-url" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#urlencoding@2.1.3", - "author": "Kornel , Bertram Truong ", - "name": "urlencoding", - "version": "2.1.3", - "description": "A Rust library for doing URL percentage encoding.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/urlencoding@2.1.3", - "externalReferences": [ - { - "type": "website", - "url": "https://lib.rs/urlencoding" - }, - { - "type": "vcs", - "url": "https://github.com/kornelski/rust_urlencoding" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#utf8_iter@1.0.4", - "author": "Henri Sivonen ", - "name": "utf8_iter", - "version": "1.0.4", - "description": "Iterator by char over potentially-invalid UTF-8 in &[u8]", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/utf8_iter@1.0.4", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/utf8_iter/" - }, - { - "type": "website", - "url": "https://docs.rs/utf8_iter/" - }, - { - "type": "vcs", - "url": "https://github.com/hsivonen/utf8_iter" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#utf8parse@0.2.2", - "author": "Joe Wilm , Christian Duerr ", - "name": "utf8parse", - "version": "0.2.2", - "description": "Table-driven UTF-8 parser", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/utf8parse@0.2.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/utf8parse/" - }, - { - "type": "vcs", - "url": "https://github.com/alacritty/vte" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#uuid@1.20.0", - "author": "Ashley Mannix, Dylan DPC, Hunar Roop Kahlon", - "name": "uuid", - "version": "1.20.0", - "description": "A library to generate and parse UUIDs.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/uuid@1.20.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/uuid" - }, - { - "type": "website", - "url": "https://github.com/uuid-rs/uuid" - }, - { - "type": "vcs", - "url": "https://github.com/uuid-rs/uuid" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.5", - "author": "Sergio Benitez ", - "name": "version_check", - "version": "0.9.5", - "description": "Tiny crate to check the version of the installed/running rustc.", - "scope": "excluded", - "hashes": [ - { - "alg": "SHA-256", - "content": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - } - ], - "licenses": [ - { - "expression": "MIT OR Apache-2.0" - } - ], - "purl": "pkg:cargo/version_check@0.9.5", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/version_check/" - }, - { - "type": "vcs", - "url": "https://github.com/SergioBenitez/version_check" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#walkdir@2.5.0", - "author": "Andrew Gallant ", - "name": "walkdir", - "version": "2.5.0", - "description": "Recursively walk a directory.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" - } - ], - "licenses": [ - { - "expression": "Unlicense OR MIT" - } - ], - "purl": "pkg:cargo/walkdir@2.5.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/walkdir/" - }, - { - "type": "website", - "url": "https://github.com/BurntSushi/walkdir" - }, - { - "type": "vcs", - "url": "https://github.com/BurntSushi/walkdir" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#want@0.3.1", - "author": "Sean McArthur ", - "name": "want", - "version": "0.3.1", - "description": "Detect when another Future wants a result.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/want@0.3.1", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/want" - }, - { - "type": "vcs", - "url": "https://github.com/seanmonstar/want" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#warp@0.4.2", - "author": "Sean McArthur ", - "name": "warp", - "version": "0.4.2", - "description": "serve the web at warp speeds", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "51d06d9202adc1f15d709c4f4a2069be5428aa912cc025d6f268ac441ab066b0" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/warp@0.4.2", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/warp" - }, - { - "type": "vcs", - "url": "https://github.com/seanmonstar/warp" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#whoami@2.1.0", - "name": "whoami", - "version": "2.1.0", - "description": "Rust library for getting information about the current user and environment", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "8fae98cf96deed1b7572272dfc777713c249ae40aa1cf8862e091e8b745f5361" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR BSL-1.0 OR MIT" - } - ], - "purl": "pkg:cargo/whoami@2.1.0", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/whoami" - }, - { - "type": "website", - "url": "https://github.com/ardaku/whoami/releases" - }, - { - "type": "vcs", - "url": "https://github.com/ardaku/whoami" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wide@0.7.33", - "author": "Lokathor ", - "name": "wide", - "version": "0.7.33", - "description": "A crate to help you go wide.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" - } - ], - "licenses": [ - { - "expression": "Zlib OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/wide@0.7.33", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/Lokathor/wide" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#winnow@0.7.14", - "name": "winnow", - "version": "0.7.14", - "description": "A byte-oriented, zero-copy, parser combinators library", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/winnow@0.7.14", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/winnow-rs/winnow" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#writeable@0.6.2", - "author": "The ICU4X Project Developers", - "name": "writeable", - "version": "0.6.2", - "description": "A more efficient alternative to fmt::Display", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/writeable@0.6.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#yoke-derive@0.8.1", - "author": "Manish Goregaokar ", - "name": "yoke-derive", - "version": "0.8.1", - "description": "Custom derive for the yoke crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/yoke-derive@0.8.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#yoke@0.8.1", - "author": "Manish Goregaokar ", - "name": "yoke", - "version": "0.8.1", - "description": "Abstraction allowing borrowed data to be carried along with the backing data it borrows from", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/yoke@0.8.1", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.8.39", - "author": "Joshua Liebow-Feeser , Jack Wrenn ", - "name": "zerocopy-derive", - "version": "0.8.39", - "description": "Custom derive for traits from the zerocopy crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" - } - ], - "licenses": [ - { - "expression": "BSD-2-Clause OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/zerocopy-derive@0.8.39", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/google/zerocopy" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.39", - "author": "Joshua Liebow-Feeser , Jack Wrenn ", - "name": "zerocopy", - "version": "0.8.39", - "description": "Zerocopy makes zero-cost memory manipulation effortless. We write \"unsafe\" so you don't have to.", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" - } - ], - "licenses": [ - { - "expression": "BSD-2-Clause OR Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/zerocopy@0.8.39", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/google/zerocopy" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom-derive@0.1.6", - "author": "Manish Goregaokar ", - "name": "zerofrom-derive", - "version": "0.1.6", - "description": "Custom derive for the zerofrom crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/zerofrom-derive@0.1.6", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.6", - "author": "Manish Goregaokar ", - "name": "zerofrom", - "version": "0.1.6", - "description": "ZeroFrom trait for constructing", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/zerofrom@0.1.6", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zeroize@1.8.2", - "author": "The RustCrypto Project Developers", - "name": "zeroize", - "version": "1.8.2", - "description": "Securely clear secrets from memory with a simple trait built on stable Rust primitives which guarantee memory is zeroed using an operation will not be 'optimized away' by the compiler. Uses a portable pure Rust implementation that works everywhere, even WASM! ", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - } - ], - "licenses": [ - { - "expression": "Apache-2.0 OR MIT" - } - ], - "purl": "pkg:cargo/zeroize@1.8.2", - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/RustCrypto/utils/tree/master/zeroize" - }, - { - "type": "vcs", - "url": "https://github.com/RustCrypto/utils" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerotrie@0.2.3", - "author": "The ICU4X Project Developers", - "name": "zerotrie", - "version": "0.2.3", - "description": "A data structure that efficiently maps strings to integers", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/zerotrie@0.2.3", - "externalReferences": [ - { - "type": "website", - "url": "https://icu4x.unicode.org" - }, - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec-derive@0.11.2", - "author": "Manish Goregaokar ", - "name": "zerovec-derive", - "version": "0.11.2", - "description": "Custom derive for the zerovec crate", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/zerovec-derive@0.11.2", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5", - "author": "The ICU4X Project Developers", - "name": "zerovec", - "version": "0.11.5", - "description": "Zero-copy vector backed by a byte array", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" - } - ], - "licenses": [ - { - "expression": "Unicode-3.0" - } - ], - "purl": "pkg:cargo/zerovec@0.11.5", - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/unicode-org/icu4x" - } - ] - }, - { - "type": "library", - "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zmij@1.0.20", - "author": "David Tolnay ", - "name": "zmij", - "version": "1.0.20", - "description": "A double-to-string conversion algorithm based on Schubfach and yy", - "scope": "required", - "hashes": [ - { - "alg": "SHA-256", - "content": "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" - } - ], - "licenses": [ - { - "expression": "MIT" - } - ], - "purl": "pkg:cargo/zmij@1.0.20", - "externalReferences": [ - { - "type": "documentation", - "url": "https://docs.rs/zmij" - }, - { - "type": "vcs", - "url": "https://github.com/dtolnay/zmij" - } - ] - } - ], - "dependencies": [ - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/cas_client#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#axum@0.8.8", - "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "path+file:///home/runner/work/xet-core/xet-core/cas_object#0.1.0", - "path+file:///home/runner/work/xet-core/xet-core/cas_types#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "registry+https://github.com/rust-lang/crates.io-index#clap@4.5.57", - "path+file:///home/runner/work/xet-core/xet-core/deduplication#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/file_utils#0.14.2", - "registry+https://github.com/rust-lang/crates.io-index#futures@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#heed@0.22.0", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "path+file:///home/runner/work/xet-core/xet-core/mdb_shard#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#reqwest@0.13.2", - "registry+https://github.com/rust-lang/crates.io-index#reqwest-middleware@0.5.1", - "registry+https://github.com/rust-lang/crates.io-index#reqwest-retry@0.9.1", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "registry+https://github.com/rust-lang/crates.io-index#statrs@0.18.0", - "registry+https://github.com/rust-lang/crates.io-index#tempfile@3.25.0", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tokio-retry@0.3.0", - "registry+https://github.com/rust-lang/crates.io-index#tower-http@0.6.8", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "registry+https://github.com/rust-lang/crates.io-index#tracing-log@0.2.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing-subscriber@0.3.22", - "registry+https://github.com/rust-lang/crates.io-index#url@2.5.8", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#warp@0.4.2", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/cas_object#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "registry+https://github.com/rust-lang/crates.io-index#blake3@1.8.3", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#clap@4.5.57", - "registry+https://github.com/rust-lang/crates.io-index#countio@0.3.0", - "registry+https://github.com/rust-lang/crates.io-index#csv@1.4.0", - "path+file:///home/runner/work/xet-core/xet-core/deduplication#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#futures@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#half@2.7.1", - "registry+https://github.com/rust-lang/crates.io-index#lz4_flex@0.12.0", - "path+file:///home/runner/work/xet-core/xet-core/mdb_shard#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/cas_types#0.1.0", - "dependsOn": [ - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_repr@0.1.20", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/data#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "path+file:///home/runner/work/xet-core/xet-core/cas_client#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/cas_object#0.1.0", - "path+file:///home/runner/work/xet-core/xet-core/cas_types#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "registry+https://github.com/rust-lang/crates.io-index#clap@4.5.57", - "path+file:///home/runner/work/xet-core/xet-core/deduplication#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/file_reconstruction#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "path+file:///home/runner/work/xet-core/xet-core/hub_client#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "path+file:///home/runner/work/xet-core/xet-core/mdb_shard#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "path+file:///home/runner/work/xet-core/xet-core/progress_tracking#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#prometheus@0.14.0", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#regex@1.12.3", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "registry+https://github.com/rust-lang/crates.io-index#sha2@0.10.9", - "registry+https://github.com/rust-lang/crates.io-index#tempfile@3.25.0", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "registry+https://github.com/rust-lang/crates.io-index#ulid@1.2.1", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#walkdir@2.5.0", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/deduplication#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#gearhash@0.1.3", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "path+file:///home/runner/work/xet-core/xet-core/mdb_shard#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "path+file:///home/runner/work/xet-core/xet-core/progress_tracking#0.1.0", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/file_reconstruction#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "path+file:///home/runner/work/xet-core/xet-core/cas_client#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/cas_types#0.1.0", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "path+file:///home/runner/work/xet-core/xet-core/progress_tracking#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_config#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/file_utils#0.14.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#colored@3.1.1", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "registry+https://github.com/rust-lang/crates.io-index#whoami@2.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/hf_xet#1.3.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "path+file:///home/runner/work/xet-core/xet-core/cas_client#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "path+file:///home/runner/work/xet-core/xet-core/data#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#itertools@0.14.0", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "path+file:///home/runner/work/xet-core/xet-core/progress_tracking#0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.26.0", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#signal-hook@0.3.18", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_config#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_logging#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/hub_client#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "path+file:///home/runner/work/xet-core/xet-core/cas_client#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#reqwest@0.13.2", - "registry+https://github.com/rust-lang/crates.io-index#reqwest-middleware@0.5.1", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#urlencoding@2.1.3" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/mdb_shard#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#blake3@1.8.3", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#clap@4.5.57", - "registry+https://github.com/rust-lang/crates.io-index#futures@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#heapify@0.2.0", - "registry+https://github.com/rust-lang/crates.io-index#itertools@0.14.0", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#regex@1.12.3", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0", - "registry+https://github.com/rust-lang/crates.io-index#tempfile@3.25.0", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#uuid@1.20.0", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "registry+https://github.com/rust-lang/crates.io-index#blake3@1.8.3", - "registry+https://github.com/rust-lang/crates.io-index#bytemuck@1.25.0", - "registry+https://github.com/rust-lang/crates.io-index#heed@0.22.0", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#safe-transmute@0.11.3", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/progress_tracking#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#bincode@1.3.3", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "registry+https://github.com/rust-lang/crates.io-index#ctor@0.6.3", - "registry+https://github.com/rust-lang/crates.io-index#derivative@2.2.0", - "registry+https://github.com/rust-lang/crates.io-index#duration-str@0.19.0", - "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#futures@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "path+file:///home/runner/work/xet-core/xet-core/merklehash#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#pin-project@1.1.10", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#shellexpand@3.1.1", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tokio-util@0.7.18", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/xet_config#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#const-str@1.1.0", - "registry+https://github.com/rust-lang/crates.io-index#konst@0.4.3", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/xet_logging#0.14.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#git-version@0.3.9", - "registry+https://github.com/rust-lang/crates.io-index#sysinfo@0.38.1", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "registry+https://github.com/rust-lang/crates.io-index#tracing-appender@0.2.4", - "registry+https://github.com/rust-lang/crates.io-index#tracing-subscriber@0.3.22", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0" - ] - }, - { - "ref": "path+file:///home/runner/work/xet-core/xet-core/xet_runtime#0.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#dirs@6.0.0", - "path+file:///home/runner/work/xet-core/xet-core/error_printer#0.14.5", - "registry+https://github.com/rust-lang/crates.io-index#oneshot@0.1.13", - "registry+https://github.com/rust-lang/crates.io-index#reqwest@0.13.2", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "path+file:///home/runner/work/xet-core/xet-core/utils#0.14.5", - "path+file:///home/runner/work/xet-core/xet-core/xet_config#0.14.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#anstream@0.6.21", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anstyle@1.0.13", - "registry+https://github.com/rust-lang/crates.io-index#anstyle-parse@0.2.7", - "registry+https://github.com/rust-lang/crates.io-index#anstyle-query@1.1.5", - "registry+https://github.com/rust-lang/crates.io-index#colorchoice@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#is_terminal_polyfill@1.70.2", - "registry+https://github.com/rust-lang/crates.io-index#utf8parse@0.2.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#anstyle-parse@0.2.7", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#utf8parse@0.2.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#anstyle-query@1.1.5", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#anstyle@1.0.13", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#approx@0.5.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#arrayref@0.3.9", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#arrayvec@0.7.6", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#atomic-waker@1.1.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.5.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#aws-lc-rs@1.15.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#aws-lc-sys@0.37.0", - "registry+https://github.com/rust-lang/crates.io-index#zeroize@1.8.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#aws-lc-sys@0.37.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55", - "registry+https://github.com/rust-lang/crates.io-index#cmake@0.1.57", - "registry+https://github.com/rust-lang/crates.io-index#dunce@1.0.5", - "registry+https://github.com/rust-lang/crates.io-index#fs_extra@1.3.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#axum-core@0.5.6", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#http-body-util@0.1.3", - "registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#sync_wrapper@1.0.2", - "registry+https://github.com/rust-lang/crates.io-index#tower-layer@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#axum@0.8.8", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#axum-core@0.5.6", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#http-body-util@0.1.3", - "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "registry+https://github.com/rust-lang/crates.io-index#hyper-util@0.1.20", - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "registry+https://github.com/rust-lang/crates.io-index#matchit@0.8.4", - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17", - "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "registry+https://github.com/rust-lang/crates.io-index#serde_path_to_error@0.1.20", - "registry+https://github.com/rust-lang/crates.io-index#serde_urlencoded@0.7.1", - "registry+https://github.com/rust-lang/crates.io-index#sync_wrapper@1.0.2", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tower@0.5.3", - "registry+https://github.com/rust-lang/crates.io-index#tower-layer@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#bincode@1.3.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.10.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#blake3@1.8.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#arrayref@0.3.9", - "registry+https://github.com/rust-lang/crates.io-index#arrayvec@0.7.6", - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55", - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#constant_time_eq@0.4.2", - "registry+https://github.com/rust-lang/crates.io-index#cpufeatures@0.2.17" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#block-buffer@0.10.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#generic-array@0.14.7" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#bstr@1.12.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.14", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#bytemuck@1.25.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#byteorder@1.5.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9", - "registry+https://github.com/rust-lang/crates.io-index#jobserver@0.1.34", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#shlex@1.3.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@0.1.10", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cfg_aliases@0.2.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#iana-time-zone@0.1.65", - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#clap@4.5.57", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#clap_builder@4.5.57", - "registry+https://github.com/rust-lang/crates.io-index#clap_derive@4.5.55" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#clap_builder@4.5.57", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anstream@0.6.21", - "registry+https://github.com/rust-lang/crates.io-index#anstyle@1.0.13", - "registry+https://github.com/rust-lang/crates.io-index#clap_lex@0.7.7", - "registry+https://github.com/rust-lang/crates.io-index#strsim@0.11.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#clap_derive@4.5.55", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#clap_lex@0.7.7", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cmake@0.1.57", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#colorchoice@1.0.4", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#colored@3.1.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#const-str@1.1.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#const_panic@0.2.15", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#typewit@1.14.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#constant_time_eq@0.4.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#countio@0.3.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#futures-io@0.3.31" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#cpufeatures@0.2.17", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#crossbeam-channel@0.5.15", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.21" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#crossbeam-queue@0.3.12", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.21" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.21", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#crypto-common@0.1.7", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#generic-array@0.14.7", - "registry+https://github.com/rust-lang/crates.io-index#typenum@1.19.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#csv-core@0.1.13", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#csv@1.4.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#csv-core@0.1.13", - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "registry+https://github.com/rust-lang/crates.io-index#ryu@1.0.23", - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#ctor-proc-macro@0.0.7", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#ctor@0.6.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#ctor-proc-macro@0.0.7", - "registry+https://github.com/rust-lang/crates.io-index#dtor@0.1.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#deranged@0.5.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#powerfmt@0.2.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#derivative@2.2.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@1.0.109" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#digest@0.10.7", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#block-buffer@0.10.4", - "registry+https://github.com/rust-lang/crates.io-index#crypto-common@0.1.7" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#dirs-sys@0.5.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#option-ext@0.2.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#dirs@6.0.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#dirs-sys@0.5.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#doxygen-rs@0.4.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#phf@0.11.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#dtor-proc-macro@0.0.6", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#dtor@0.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#dtor-proc-macro@0.0.6" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#dunce@1.0.5", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#duration-str@0.19.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#chrono@0.4.43", - "registry+https://github.com/rust-lang/crates.io-index#rust_decimal@1.40.0", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#time@0.3.47", - "registry+https://github.com/rust-lang/crates.io-index#winnow@0.7.14" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#either@1.15.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#equivalent@1.0.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#errno@0.3.14", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#fastrand@2.3.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#fnv@1.0.7", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#fs_extra@1.3.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-channel@0.3.31", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.31" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-executor@0.3.31", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-task@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-io@0.3.31", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-macro@0.3.31", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.31", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-task@0.3.31", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#futures-channel@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-io@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-macro@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-task@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#pin-utils@0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#slab@0.4.12" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#futures@0.3.31", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#futures-channel@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-executor@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-io@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-task@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#gearhash@0.1.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@0.1.10" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#generic-array@0.14.7", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#typenum@1.19.0", - "registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.2.17", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.3.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.4.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#git-version-macro@0.3.9", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#git-version@0.3.9", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#git-version-macro@0.3.9" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#h2@0.4.13", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#atomic-waker@1.1.2", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#fnv@1.0.7", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#indexmap@2.13.0", - "registry+https://github.com/rust-lang/crates.io-index#slab@0.4.12", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tokio-util@0.7.18", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#half@2.7.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.39" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.16.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#headers-core@0.3.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#headers@0.4.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#headers-core@0.3.0", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#httpdate@1.0.3", - "registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17", - "registry+https://github.com/rust-lang/crates.io-index#sha1@0.10.6" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#heapify@0.2.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#heed-traits@0.20.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#heed-types@0.21.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bincode@1.3.3", - "registry+https://github.com/rust-lang/crates.io-index#byteorder@1.5.0", - "registry+https://github.com/rust-lang/crates.io-index#heed-traits@0.20.0", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#heed@0.22.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.10.0", - "registry+https://github.com/rust-lang/crates.io-index#byteorder@1.5.0", - "registry+https://github.com/rust-lang/crates.io-index#heed-traits@0.20.0", - "registry+https://github.com/rust-lang/crates.io-index#heed-types@0.21.0", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#lmdb-master-sys@0.2.5", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "registry+https://github.com/rust-lang/crates.io-index#page_size@0.6.0", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#synchronoise@1.0.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#http-body-util@0.1.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#httparse@1.10.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#httpdate@1.0.3", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#hyper-rustls@0.27.7", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "registry+https://github.com/rust-lang/crates.io-index#hyper-util@0.1.20", - "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "registry+https://github.com/rust-lang/crates.io-index#rustls-pki-types@1.14.0", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tokio-rustls@0.26.4", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#hyper-util@0.1.20", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-channel@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "registry+https://github.com/rust-lang/crates.io-index#ipnet@2.11.0", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#socket2@0.6.2", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#atomic-waker@1.1.2", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-channel@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#h2@0.4.13", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#httparse@1.10.1", - "registry+https://github.com/rust-lang/crates.io-index#httpdate@1.0.3", - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#pin-utils@0.1.0", - "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#want@0.3.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#iana-time-zone@0.1.65", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_collections@2.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", - "registry+https://github.com/rust-lang/crates.io-index#potential_utf@0.1.4", - "registry+https://github.com/rust-lang/crates.io-index#yoke@0.8.1", - "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.6", - "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locale_core@2.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", - "registry+https://github.com/rust-lang/crates.io-index#litemap@0.8.1", - "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.8.2", - "registry+https://github.com/rust-lang/crates.io-index#writeable@0.6.2", - "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer@2.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#icu_collections@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer_data@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#icu_properties@2.1.2", - "registry+https://github.com/rust-lang/crates.io-index#icu_provider@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", - "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer_data@2.1.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties@2.1.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#icu_collections@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#icu_locale_core@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#icu_properties_data@2.1.2", - "registry+https://github.com/rust-lang/crates.io-index#icu_provider@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#zerotrie@0.2.3", - "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties_data@2.1.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_provider@2.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", - "registry+https://github.com/rust-lang/crates.io-index#icu_locale_core@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#writeable@0.6.2", - "registry+https://github.com/rust-lang/crates.io-index#yoke@0.8.1", - "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.6", - "registry+https://github.com/rust-lang/crates.io-index#zerotrie@0.2.3", - "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#idna@1.1.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#idna_adapter@1.2.1", - "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", - "registry+https://github.com/rust-lang/crates.io-index#utf8_iter@1.0.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#idna_adapter@1.2.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#icu_properties@2.1.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#indexmap@2.13.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#equivalent@1.0.2", - "registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.16.1", - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#indoc@2.0.7", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#rustversion@1.0.22" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#ipnet@2.11.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#iri-string@0.7.10", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#is_terminal_polyfill@1.70.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#itertools@0.14.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#either@1.15.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#jobserver@0.1.34", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#konst@0.4.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#const_panic@0.2.15", - "registry+https://github.com/rust-lang/crates.io-index#konst_proc_macros@0.4.1", - "registry+https://github.com/rust-lang/crates.io-index#typewit@1.14.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#konst_proc_macros@0.4.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#libm@0.2.16", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#linux-raw-sys@0.11.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#litemap@0.8.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#lmdb-master-sys@0.2.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55", - "registry+https://github.com/rust-lang/crates.io-index#doxygen-rs@0.4.2", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#lock_api@0.4.14", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#scopeguard@1.2.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#log@0.4.29", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#lru-slab@0.1.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#lz4_flex@0.12.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#twox-hash@2.1.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#matchers@0.2.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.14" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#matchit@0.8.4", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#matrixmultiply@0.3.10", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.5.0", - "registry+https://github.com/rust-lang/crates.io-index#rawpointer@0.2.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#memoffset@0.9.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.5.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#mime_guess@2.0.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17", - "registry+https://github.com/rust-lang/crates.io-index#unicase@2.9.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#mio@1.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#more-asserts@0.3.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#nalgebra@0.33.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#approx@0.5.1", - "registry+https://github.com/rust-lang/crates.io-index#matrixmultiply@0.3.10", - "registry+https://github.com/rust-lang/crates.io-index#num-complex@0.4.6", - "registry+https://github.com/rust-lang/crates.io-index#num-rational@0.4.2", - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5", - "registry+https://github.com/rust-lang/crates.io-index#rand_distr@0.4.3", - "registry+https://github.com/rust-lang/crates.io-index#simba@0.9.1", - "registry+https://github.com/rust-lang/crates.io-index#typenum@1.19.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#nu-ansi-term@0.50.3", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.46", - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#num-complex@0.4.6", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#num-conv@0.2.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.46", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#num-rational@0.4.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", - "registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.46", - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.5.0", - "registry+https://github.com/rust-lang/crates.io-index#libm@0.2.16" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#oneshot@0.1.13", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-probe@0.2.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#option-ext@0.2.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#os_str_bytes@6.6.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#page_size@0.6.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#parking_lot@0.12.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#lock_api@0.4.14", - "registry+https://github.com/rust-lang/crates.io-index#parking_lot_core@0.9.12" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#parking_lot_core@0.9.12", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#paste@1.0.15", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#phf@0.11.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#phf_macros@0.11.3", - "registry+https://github.com/rust-lang/crates.io-index#phf_shared@0.11.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#phf_generator@0.11.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#phf_shared@0.11.3", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#phf_macros@0.11.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#phf_generator@0.11.3", - "registry+https://github.com/rust-lang/crates.io-index#phf_shared@0.11.3", - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#phf_shared@0.11.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#siphasher@1.0.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pin-project-internal@1.1.10", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pin-project@1.1.10", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#pin-project-internal@1.1.10" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pin-utils@0.1.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#potential_utf@0.1.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#powerfmt@0.2.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#ppv-lite86@0.2.21", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.39" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.23" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#prometheus@0.14.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#fnv@1.0.7", - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0", - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#parking_lot@0.12.5", - "registry+https://github.com/rust-lang/crates.io-index#protobuf@3.7.2", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#protobuf-support@3.7.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#thiserror@1.0.69" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#protobuf@3.7.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "registry+https://github.com/rust-lang/crates.io-index#protobuf-support@3.7.2", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@1.0.69" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.26.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.26.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.26.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.26.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.26.0", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.26.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.26.0", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.26.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#indoc@2.0.7", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#memoffset@0.9.1", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.26.0", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.26.0", - "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.26.0", - "registry+https://github.com/rust-lang/crates.io-index#unindent@0.2.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#quinn-proto@0.11.13", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#aws-lc-rs@1.15.4", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#lru-slab@0.1.2", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "registry+https://github.com/rust-lang/crates.io-index#rustc-hash@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "registry+https://github.com/rust-lang/crates.io-index#slab@0.4.12", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tinyvec@1.10.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#quinn-udp@0.5.14", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg_aliases@0.2.1", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#socket2@0.6.2", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#quinn@0.11.9", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#cfg_aliases@0.2.1", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#quinn-proto@0.11.13", - "registry+https://github.com/rust-lang/crates.io-index#quinn-udp@0.5.14", - "registry+https://github.com/rust-lang/crates.io-index#rustc-hash@2.1.1", - "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "registry+https://github.com/rust-lang/crates.io-index#socket2@0.6.2", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.3.1", - "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.6.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.9.0", - "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.9.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.3.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#ppv-lite86@0.2.21", - "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.6.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rand_chacha@0.9.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#ppv-lite86@0.2.21", - "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.9.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.6.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.2.17" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rand_core@0.9.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.3.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rand_distr@0.4.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rawpointer@0.2.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.14", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.4", - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.9" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.9", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#regex@1.12.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.4", - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.14", - "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.9" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#reqwest-middleware@0.5.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#reqwest@0.13.2", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#reqwest-retry@0.9.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#anyhow@1.0.101", - "registry+https://github.com/rust-lang/crates.io-index#async-trait@0.1.89", - "registry+https://github.com/rust-lang/crates.io-index#futures@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "registry+https://github.com/rust-lang/crates.io-index#reqwest@0.13.2", - "registry+https://github.com/rust-lang/crates.io-index#reqwest-middleware@0.5.1", - "registry+https://github.com/rust-lang/crates.io-index#retry-policies@0.5.1", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#reqwest@0.13.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#http-body-util@0.1.3", - "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "registry+https://github.com/rust-lang/crates.io-index#hyper-rustls@0.27.7", - "registry+https://github.com/rust-lang/crates.io-index#hyper-util@0.1.20", - "registry+https://github.com/rust-lang/crates.io-index#log@0.4.29", - "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#quinn@0.11.9", - "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "registry+https://github.com/rust-lang/crates.io-index#rustls-pki-types@1.14.0", - "registry+https://github.com/rust-lang/crates.io-index#rustls-platform-verifier@0.6.2", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "registry+https://github.com/rust-lang/crates.io-index#sync_wrapper@1.0.2", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tokio-rustls@0.26.4", - "registry+https://github.com/rust-lang/crates.io-index#tokio-util@0.7.18", - "registry+https://github.com/rust-lang/crates.io-index#tower@0.5.3", - "registry+https://github.com/rust-lang/crates.io-index#tower-http@0.6.8", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#url@2.5.8" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#retry-policies@0.5.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#ring@0.17.14", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55", - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.2.17", - "registry+https://github.com/rust-lang/crates.io-index#untrusted@0.9.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rust_decimal@1.40.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#arrayvec@0.7.6", - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustc-hash@2.1.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustix@1.1.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.10.0", - "registry+https://github.com/rust-lang/crates.io-index#errno@0.3.14", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#linux-raw-sys@0.11.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-native-certs@0.8.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#openssl-probe@0.2.1", - "registry+https://github.com/rust-lang/crates.io-index#rustls-pki-types@1.14.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-pki-types@1.14.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#zeroize@1.8.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-platform-verifier@0.6.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#log@0.4.29", - "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "registry+https://github.com/rust-lang/crates.io-index#rustls-native-certs@0.8.3", - "registry+https://github.com/rust-lang/crates.io-index#rustls-webpki@0.103.9" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustls-webpki@0.103.9", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#aws-lc-rs@1.15.4", - "registry+https://github.com/rust-lang/crates.io-index#ring@0.17.14", - "registry+https://github.com/rust-lang/crates.io-index#rustls-pki-types@1.14.0", - "registry+https://github.com/rust-lang/crates.io-index#untrusted@0.9.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#aws-lc-rs@1.15.4", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "registry+https://github.com/rust-lang/crates.io-index#rustls-pki-types@1.14.0", - "registry+https://github.com/rust-lang/crates.io-index#rustls-webpki@0.103.9", - "registry+https://github.com/rust-lang/crates.io-index#subtle@2.6.1", - "registry+https://github.com/rust-lang/crates.io-index#zeroize@1.8.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#rustversion@1.0.22", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#ryu@1.0.23", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#safe-transmute@0.11.3", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#safe_arch@0.7.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytemuck@1.25.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#same-file@1.0.6", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#scoped-tls@1.0.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#scopeguard@1.2.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0", - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#zmij@1.0.20" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_path_to_error@0.1.20", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_repr@0.1.20", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_urlencoded@0.7.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "registry+https://github.com/rust-lang/crates.io-index#ryu@1.0.23", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#sha1@0.10.6", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#cpufeatures@0.2.17", - "registry+https://github.com/rust-lang/crates.io-index#digest@0.10.7" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#sha2-asm@0.6.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cc@1.2.55" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#sha2@0.10.9", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", - "registry+https://github.com/rust-lang/crates.io-index#cpufeatures@0.2.17", - "registry+https://github.com/rust-lang/crates.io-index#digest@0.10.7", - "registry+https://github.com/rust-lang/crates.io-index#sha2-asm@0.6.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#sharded-slab@0.1.7", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#lazy_static@1.5.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#shellexpand@3.1.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bstr@1.12.1", - "registry+https://github.com/rust-lang/crates.io-index#dirs@6.0.0", - "registry+https://github.com/rust-lang/crates.io-index#os_str_bytes@6.6.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@1.3.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#signal-hook-registry@1.4.8", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#errno@0.3.14", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#signal-hook@0.3.18", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#signal-hook-registry@1.4.8" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#simba@0.9.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#approx@0.5.1", - "registry+https://github.com/rust-lang/crates.io-index#num-complex@0.4.6", - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", - "registry+https://github.com/rust-lang/crates.io-index#paste@1.0.15", - "registry+https://github.com/rust-lang/crates.io-index#wide@0.7.33" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#siphasher@1.0.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#slab@0.4.12", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#socket2@0.6.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#stable_deref_trait@1.2.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#statrs@0.18.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#approx@0.5.1", - "registry+https://github.com/rust-lang/crates.io-index#nalgebra@0.33.2", - "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#strsim@0.11.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#subtle@2.6.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#syn@1.0.109", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.23" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.23" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#sync_wrapper@1.0.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#synchronoise@1.0.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#crossbeam-queue@0.3.12" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#sysinfo@0.38.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.4", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tempfile@3.25.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#fastrand@2.3.0", - "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.4.1", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "registry+https://github.com/rust-lang/crates.io-index#rustix@1.1.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror-impl@1.0.69", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror-impl@2.0.18", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror@1.0.69", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#thiserror-impl@1.0.69" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#thiserror-impl@2.0.18" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#thread_local@1.1.9", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#time-core@0.1.8", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#time-macros@0.2.27", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#num-conv@0.2.0", - "registry+https://github.com/rust-lang/crates.io-index#time-core@0.1.8" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#time@0.3.47", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#deranged@0.5.5", - "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.17", - "registry+https://github.com/rust-lang/crates.io-index#num-conv@0.2.0", - "registry+https://github.com/rust-lang/crates.io-index#powerfmt@0.2.0", - "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#time-core@0.1.8", - "registry+https://github.com/rust-lang/crates.io-index#time-macros@0.2.27" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.8.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", - "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tinyvec@1.10.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#tinyvec_macros@0.1.1" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tinyvec_macros@0.1.1", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-macros@2.6.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-retry@0.3.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#pin-project@1.1.10", - "registry+https://github.com/rust-lang/crates.io-index#rand@0.8.5", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-rustls@0.26.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#rustls@0.23.36", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tokio-util@0.7.18", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-sink@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.181", - "registry+https://github.com/rust-lang/crates.io-index#mio@1.1.1", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#socket2@0.6.2", - "registry+https://github.com/rust-lang/crates.io-index#tokio-macros@2.6.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tower-http@0.6.8", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.10.0", - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#iri-string@0.7.10", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#tower@0.5.3", - "registry+https://github.com/rust-lang/crates.io-index#tower-layer@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tower-layer@0.3.3", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tower@0.5.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#futures-core@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#sync_wrapper@1.0.2", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tower-layer@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-appender@0.2.4", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#crossbeam-channel@0.5.15", - "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.18", - "registry+https://github.com/rust-lang/crates.io-index#time@0.3.47", - "registry+https://github.com/rust-lang/crates.io-index#tracing-subscriber@0.3.22" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-attributes@0.1.31", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-core@0.1.36", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-log@0.2.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#log@0.4.29", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "registry+https://github.com/rust-lang/crates.io-index#tracing-core@0.1.36" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-serde@0.2.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#tracing-core@0.1.36" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tracing-subscriber@0.3.22", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#matchers@0.2.0", - "registry+https://github.com/rust-lang/crates.io-index#nu-ansi-term@0.50.3", - "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", - "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.14", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "registry+https://github.com/rust-lang/crates.io-index#sharded-slab@0.1.7", - "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", - "registry+https://github.com/rust-lang/crates.io-index#thread_local@1.1.9", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "registry+https://github.com/rust-lang/crates.io-index#tracing-core@0.1.36", - "registry+https://github.com/rust-lang/crates.io-index#tracing-log@0.2.0", - "registry+https://github.com/rust-lang/crates.io-index#tracing-serde@0.2.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#log@0.4.29", - "registry+https://github.com/rust-lang/crates.io-index#pin-project-lite@0.2.16", - "registry+https://github.com/rust-lang/crates.io-index#tracing-attributes@0.1.31", - "registry+https://github.com/rust-lang/crates.io-index#tracing-core@0.1.36" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#try-lock@0.2.5", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#twox-hash@2.1.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#typenum@1.19.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#typewit@1.14.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#ulid@1.2.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#rand@0.9.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#unicase@2.9.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.23", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#unindent@0.2.4", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#untrusted@0.9.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#url@2.5.8", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", - "registry+https://github.com/rust-lang/crates.io-index#idna@1.1.0", - "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#urlencoding@2.1.3", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#utf8_iter@1.0.4", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#utf8parse@0.2.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#uuid@1.20.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.3.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.5", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#walkdir@2.5.0", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#same-file@1.0.6" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#want@0.3.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#try-lock@0.2.5" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#warp@0.4.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytes@1.11.1", - "registry+https://github.com/rust-lang/crates.io-index#futures-util@0.3.31", - "registry+https://github.com/rust-lang/crates.io-index#headers@0.4.1", - "registry+https://github.com/rust-lang/crates.io-index#http@1.4.0", - "registry+https://github.com/rust-lang/crates.io-index#http-body@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#http-body-util@0.1.3", - "registry+https://github.com/rust-lang/crates.io-index#hyper@1.8.1", - "registry+https://github.com/rust-lang/crates.io-index#hyper-util@0.1.20", - "registry+https://github.com/rust-lang/crates.io-index#log@0.4.29", - "registry+https://github.com/rust-lang/crates.io-index#mime@0.3.17", - "registry+https://github.com/rust-lang/crates.io-index#mime_guess@2.0.5", - "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", - "registry+https://github.com/rust-lang/crates.io-index#pin-project@1.1.10", - "registry+https://github.com/rust-lang/crates.io-index#scoped-tls@1.0.1", - "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", - "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", - "registry+https://github.com/rust-lang/crates.io-index#serde_urlencoded@0.7.1", - "registry+https://github.com/rust-lang/crates.io-index#tokio@1.49.0", - "registry+https://github.com/rust-lang/crates.io-index#tokio-util@0.7.18", - "registry+https://github.com/rust-lang/crates.io-index#tower-service@0.3.3", - "registry+https://github.com/rust-lang/crates.io-index#tracing@0.1.44" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#whoami@2.1.0", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#wide@0.7.33", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#bytemuck@1.25.0", - "registry+https://github.com/rust-lang/crates.io-index#safe_arch@0.7.4" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#winnow@0.7.14", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#memchr@2.8.0" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#writeable@0.6.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#yoke-derive@0.8.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114", - "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#yoke@0.8.1", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#stable_deref_trait@1.2.1", - "registry+https://github.com/rust-lang/crates.io-index#yoke-derive@0.8.1", - "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.6" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.8.39", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.39", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.8.39" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom-derive@0.1.6", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114", - "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.6", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#zerofrom-derive@0.1.6" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zeroize@1.8.2", - "dependsOn": [] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zerotrie@0.2.3", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", - "registry+https://github.com/rust-lang/crates.io-index#yoke@0.8.1", - "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.6" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec-derive@0.11.2", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.106", - "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", - "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.114" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.11.5", - "dependsOn": [ - "registry+https://github.com/rust-lang/crates.io-index#yoke@0.8.1", - "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.6", - "registry+https://github.com/rust-lang/crates.io-index#zerovec-derive@0.11.2" - ] - }, - { - "ref": "registry+https://github.com/rust-lang/crates.io-index#zmij@1.0.20", - "dependsOn": [] - } - ] -} \ No newline at end of file diff --git a/venv/lib/python3.10/site-packages/hf_xet/__init__.py b/venv/lib/python3.10/site-packages/hf_xet/__init__.py deleted file mode 100644 index 96ed54a8a066d681e4973e5841a0f5577b619698..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .hf_xet import * - -__doc__ = hf_xet.__doc__ -if hasattr(hf_xet, "__all__"): - __all__ = hf_xet.__all__ \ No newline at end of file diff --git a/venv/lib/python3.10/site-packages/hf_xet/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/hf_xet/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 97adc22a1cd34226e9ea4abba6d222c454c635e7..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/hf_xet/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/hf_xet/hf_xet.abi3.so b/venv/lib/python3.10/site-packages/hf_xet/hf_xet.abi3.so deleted file mode 100644 index 1edadd90c398d8d4116c88b9b0b0dda241284d15..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/hf_xet/hf_xet.abi3.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:acd592c734655b46338cec117cc020cc013cd075db016dff1d1f276acfb658e8 -size 10589672 diff --git a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/METADATA b/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/METADATA deleted file mode 100644 index 8056834e6714b089ef49847820064a1ae4b041fd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/METADATA +++ /dev/null @@ -1,625 +0,0 @@ -Metadata-Version: 2.4 -Name: httpcore -Version: 1.0.9 -Summary: A minimal low-level HTTP client. -Project-URL: Documentation, https://www.encode.io/httpcore -Project-URL: Homepage, https://www.encode.io/httpcore/ -Project-URL: Source, https://github.com/encode/httpcore -Author-email: Tom Christie -License-Expression: BSD-3-Clause -License-File: LICENSE.md -Classifier: Development Status :: 3 - Alpha -Classifier: Environment :: Web Environment -Classifier: Framework :: AsyncIO -Classifier: Framework :: Trio -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.8 -Requires-Dist: certifi -Requires-Dist: h11>=0.16 -Provides-Extra: asyncio -Requires-Dist: anyio<5.0,>=4.0; extra == 'asyncio' -Provides-Extra: http2 -Requires-Dist: h2<5,>=3; extra == 'http2' -Provides-Extra: socks -Requires-Dist: socksio==1.*; extra == 'socks' -Provides-Extra: trio -Requires-Dist: trio<1.0,>=0.22.0; extra == 'trio' -Description-Content-Type: text/markdown - -# HTTP Core - -[![Test Suite](https://github.com/encode/httpcore/workflows/Test%20Suite/badge.svg)](https://github.com/encode/httpcore/actions) -[![Package version](https://badge.fury.io/py/httpcore.svg)](https://pypi.org/project/httpcore/) - -> *Do one thing, and do it well.* - -The HTTP Core package provides a minimal low-level HTTP client, which does -one thing only. Sending HTTP requests. - -It does not provide any high level model abstractions over the API, -does not handle redirects, multipart uploads, building authentication headers, -transparent HTTP caching, URL parsing, session cookie handling, -content or charset decoding, handling JSON, environment based configuration -defaults, or any of that Jazz. - -Some things HTTP Core does do: - -* Sending HTTP requests. -* Thread-safe / task-safe connection pooling. -* HTTP(S) proxy & SOCKS proxy support. -* Supports HTTP/1.1 and HTTP/2. -* Provides both sync and async interfaces. -* Async backend support for `asyncio` and `trio`. - -## Requirements - -Python 3.8+ - -## Installation - -For HTTP/1.1 only support, install with: - -```shell -$ pip install httpcore -``` - -There are also a number of optional extras available... - -```shell -$ pip install httpcore['asyncio,trio,http2,socks'] -``` - -## Sending requests - -Send an HTTP request: - -```python -import httpcore - -response = httpcore.request("GET", "https://www.example.com/") - -print(response) -# -print(response.status) -# 200 -print(response.headers) -# [(b'Accept-Ranges', b'bytes'), (b'Age', b'557328'), (b'Cache-Control', b'max-age=604800'), ...] -print(response.content) -# b'\n\n\nExample Domain\n\n\n ...' -``` - -The top-level `httpcore.request()` function is provided for convenience. In practice whenever you're working with `httpcore` you'll want to use the connection pooling functionality that it provides. - -```python -import httpcore - -http = httpcore.ConnectionPool() -response = http.request("GET", "https://www.example.com/") -``` - -Once you're ready to get going, [head over to the documentation](https://www.encode.io/httpcore/). - -## Motivation - -You *probably* don't want to be using HTTP Core directly. It might make sense if -you're writing something like a proxy service in Python, and you just want -something at the lowest possible level, but more typically you'll want to use -a higher level client library, such as `httpx`. - -The motivation for `httpcore` is: - -* To provide a reusable low-level client library, that other packages can then build on top of. -* To provide a *really clear interface split* between the networking code and client logic, - so that each is easier to understand and reason about in isolation. - -## Dependencies - -The `httpcore` package has the following dependencies... - -* `h11` -* `certifi` - -And the following optional extras... - -* `anyio` - Required by `pip install httpcore['asyncio']`. -* `trio` - Required by `pip install httpcore['trio']`. -* `h2` - Required by `pip install httpcore['http2']`. -* `socksio` - Required by `pip install httpcore['socks']`. - -## Versioning - -We use [SEMVER for our versioning policy](https://semver.org/). - -For changes between package versions please see our [project changelog](CHANGELOG.md). - -We recommend pinning your requirements either the most current major version, or a more specific version range: - -```python -pip install 'httpcore==1.*' -``` -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - -## Version 1.0.9 (April 24th, 2025) - -- Resolve https://github.com/advisories/GHSA-vqfr-h8mv-ghfj with h11 dependency update. (#1008) - -## Version 1.0.8 (April 11th, 2025) - -- Fix `AttributeError` when importing on Python 3.14. (#1005) - -## Version 1.0.7 (November 15th, 2024) - -- Support `proxy=…` configuration on `ConnectionPool()`. (#974) - -## Version 1.0.6 (October 1st, 2024) - -- Relax `trio` dependency pinning. (#956) -- Handle `trio` raising `NotImplementedError` on unsupported platforms. (#955) -- Handle mapping `ssl.SSLError` to `httpcore.ConnectError`. (#918) - -## 1.0.5 (March 27th, 2024) - -- Handle `EndOfStream` exception for anyio backend. (#899) -- Allow trio `0.25.*` series in package dependancies. (#903) - -## 1.0.4 (February 21st, 2024) - -- Add `target` request extension. (#888) -- Fix support for connection `Upgrade` and `CONNECT` when some data in the stream has been read. (#882) - -## 1.0.3 (February 13th, 2024) - -- Fix support for async cancellations. (#880) -- Fix trace extension when used with socks proxy. (#849) -- Fix SSL context for connections using the "wss" scheme (#869) - -## 1.0.2 (November 10th, 2023) - -- Fix `float("inf")` timeouts in `Event.wait` function. (#846) - -## 1.0.1 (November 3rd, 2023) - -- Fix pool timeout to account for the total time spent retrying. (#823) -- Raise a neater RuntimeError when the correct async deps are not installed. (#826) -- Add support for synchronous TLS-in-TLS streams. (#840) - -## 1.0.0 (October 6th, 2023) - -From version 1.0 our async support is now optional, as the package has minimal dependencies by default. - -For async support use either `pip install 'httpcore[asyncio]'` or `pip install 'httpcore[trio]'`. - -The project versioning policy is now explicitly governed by SEMVER. See https://semver.org/. - -- Async support becomes fully optional. (#809) -- Add support for Python 3.12. (#807) - -## 0.18.0 (September 8th, 2023) - -- Add support for HTTPS proxies. (#745, #786) -- Drop Python 3.7 support. (#727) -- Handle `sni_hostname` extension with SOCKS proxy. (#774) -- Handle HTTP/1.1 half-closed connections gracefully. (#641) -- Change the type of `Extensions` from `Mapping[Str, Any]` to `MutableMapping[Str, Any]`. (#762) - -## 0.17.3 (July 5th, 2023) - -- Support async cancellations, ensuring that the connection pool is left in a clean state when cancellations occur. (#726) -- The networking backend interface has [been added to the public API](https://www.encode.io/httpcore/network-backends). Some classes which were previously private implementation detail are now part of the top-level public API. (#699) -- Graceful handling of HTTP/2 GoAway frames, with requests being transparently retried on a new connection. (#730) -- Add exceptions when a synchronous `trace callback` is passed to an asynchronous request or an asynchronous `trace callback` is passed to a synchronous request. (#717) -- Drop Python 3.7 support. (#727) - -## 0.17.2 (May 23th, 2023) - -- Add `socket_options` argument to `ConnectionPool` and `HTTProxy` classes. (#668) -- Improve logging with per-module logger names. (#690) -- Add `sni_hostname` request extension. (#696) -- Resolve race condition during import of `anyio` package. (#692) -- Enable TCP_NODELAY for all synchronous sockets. (#651) - -## 0.17.1 (May 17th, 2023) - -- If 'retries' is set, then allow retries if an SSL handshake error occurs. (#669) -- Improve correctness of tracebacks on network exceptions, by raising properly chained exceptions. (#678) -- Prevent connection-hanging behaviour when HTTP/2 connections are closed by a server-sent 'GoAway' frame. (#679) -- Fix edge-case exception when removing requests from the connection pool. (#680) -- Fix pool timeout edge-case. (#688) - -## 0.17.0 (March 16th, 2023) - -- Add DEBUG level logging. (#648) -- Respect HTTP/2 max concurrent streams when settings updates are sent by server. (#652) -- Increase the allowable HTTP header size to 100kB. (#647) -- Add `retries` option to SOCKS proxy classes. (#643) - -## 0.16.3 (December 20th, 2022) - -- Allow `ws` and `wss` schemes. Allows us to properly support websocket upgrade connections. (#625) -- Forwarding HTTP proxies use a connection-per-remote-host. Required by some proxy implementations. (#637) -- Don't raise `RuntimeError` when closing a connection pool with active connections. Removes some error cases when cancellations are used. (#631) -- Lazy import `anyio`, so that it's no longer a hard dependancy, and isn't imported if unused. (#639) - -## 0.16.2 (November 25th, 2022) - -- Revert 'Fix async cancellation behaviour', which introduced race conditions. (#627) -- Raise `RuntimeError` if attempting to us UNIX domain sockets on Windows. (#619) - -## 0.16.1 (November 17th, 2022) - -- Fix HTTP/1.1 interim informational responses, such as "100 Continue". (#605) - -## 0.16.0 (October 11th, 2022) - -- Support HTTP/1.1 informational responses. (#581) -- Fix async cancellation behaviour. (#580) -- Support `h11` 0.14. (#579) - -## 0.15.0 (May 17th, 2022) - -- Drop Python 3.6 support (#535) -- Ensure HTTP proxy CONNECT requests include `timeout` configuration. (#506) -- Switch to explicit `typing.Optional` for type hints. (#513) -- For `trio` map OSError exceptions to `ConnectError`. (#543) - -## 0.14.7 (February 4th, 2022) - -- Requests which raise a PoolTimeout need to be removed from the pool queue. (#502) -- Fix AttributeError that happened when Socks5Connection were terminated. (#501) - -## 0.14.6 (February 1st, 2022) - -- Fix SOCKS support for `http://` URLs. (#492) -- Resolve race condition around exceptions during streaming a response. (#491) - -## 0.14.5 (January 18th, 2022) - -- SOCKS proxy support. (#478) -- Add proxy_auth argument to HTTPProxy. (#481) -- Improve error message on 'RemoteProtocolError' exception when server disconnects without sending a response. (#479) - -## 0.14.4 (January 5th, 2022) - -- Support HTTP/2 on HTTPS tunnelling proxies. (#468) -- Fix proxy headers missing on HTTP forwarding. (#456) -- Only instantiate SSL context if required. (#457) -- More robust HTTP/2 handling. (#253, #439, #440, #441) - -## 0.14.3 (November 17th, 2021) - -- Fix race condition when removing closed connections from the pool. (#437) - -## 0.14.2 (November 16th, 2021) - -- Failed connections no longer remain in the pool. (Pull #433) - -## 0.14.1 (November 12th, 2021) - -- `max_connections` becomes optional. (Pull #429) -- `certifi` is now included in the install dependancies. (Pull #428) -- `h2` is now strictly optional. (Pull #428) - -## 0.14.0 (November 11th, 2021) - -The 0.14 release is a complete reworking of `httpcore`, comprehensively addressing some underlying issues in the connection pooling, as well as substantially redesigning the API to be more user friendly. - -Some of the lower-level API design also makes the components more easily testable in isolation, and the package now has 100% test coverage. - -See [discussion #419](https://github.com/encode/httpcore/discussions/419) for a little more background. - -There's some other neat bits in there too, such as the "trace" extension, which gives a hook into inspecting the internal events that occur during the request/response cycle. This extension is needed for the HTTPX cli, in order to... - -* Log the point at which the connection is established, and the IP/port on which it is made. -* Determine if the outgoing request should log as HTTP/1.1 or HTTP/2, rather than having to assume it's HTTP/2 if the --http2 flag was passed. (Which may not actually be true.) -* Log SSL version info / certificate info. - -Note that `curio` support is not currently available in 0.14.0. If you're using `httpcore` with `curio` please get in touch, so we can assess if we ought to prioritize it as a feature or not. - -## 0.13.7 (September 13th, 2021) - -- Fix broken error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #403) - -## 0.13.6 (June 15th, 2021) - -### Fixed - -- Close sockets when read or write timeouts occur. (Pull #365) - -## 0.13.5 (June 14th, 2021) - -### Fixed - -- Resolved niggles with AnyIO EOF behaviours. (Pull #358, #362) - -## 0.13.4 (June 9th, 2021) - -### Added - -- Improved error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #354) - -### Fixed - -- Switched to `anyio` as the default backend implementation when running with `asyncio`. Resolves some awkward [TLS timeout issues](https://github.com/encode/httpx/discussions/1511). - -## 0.13.3 (May 6th, 2021) - -### Added - -- Support HTTP/2 prior knowledge, using `httpcore.SyncConnectionPool(http1=False)`. (Pull #333) - -### Fixed - -- Handle cases where environment does not provide `select.poll` support. (Pull #331) - -## 0.13.2 (April 29th, 2021) - -### Added - -- Improve error message for specific case of `RemoteProtocolError` where server disconnects without sending a response. (Pull #313) - -## 0.13.1 (April 28th, 2021) - -### Fixed - -- More resiliant testing for closed connections. (Pull #311) -- Don't raise exceptions on ungraceful connection closes. (Pull #310) - -## 0.13.0 (April 21st, 2021) - -The 0.13 release updates the core API in order to match the HTTPX Transport API, -introduced in HTTPX 0.18 onwards. - -An example of making requests with the new interface is: - -```python -with httpcore.SyncConnectionPool() as http: - status_code, headers, stream, extensions = http.handle_request( - method=b'GET', - url=(b'https', b'example.org', 443, b'/'), - headers=[(b'host', b'example.org'), (b'user-agent', b'httpcore')] - stream=httpcore.ByteStream(b''), - extensions={} - ) - body = stream.read() - print(status_code, body) -``` - -### Changed - -- The `.request()` method is now `handle_request()`. (Pull #296) -- The `.arequest()` method is now `.handle_async_request()`. (Pull #296) -- The `headers` argument is no longer optional. (Pull #296) -- The `stream` argument is no longer optional. (Pull #296) -- The `ext` argument is now named `extensions`, and is no longer optional. (Pull #296) -- The `"reason"` extension keyword is now named `"reason_phrase"`. (Pull #296) -- The `"reason_phrase"` and `"http_version"` extensions now use byte strings for their values. (Pull #296) -- The `httpcore.PlainByteStream()` class becomes `httpcore.ByteStream()`. (Pull #296) - -### Added - -- Streams now support a `.read()` interface. (Pull #296) - -### Fixed - -- Task cancellation no longer leaks connections from the connection pool. (Pull #305) - -## 0.12.3 (December 7th, 2020) - -### Fixed - -- Abort SSL connections on close rather than waiting for remote EOF when using `asyncio`. (Pull #167) -- Fix exception raised in case of connect timeouts when using the `anyio` backend. (Pull #236) -- Fix `Host` header precedence for `:authority` in HTTP/2. (Pull #241, #243) -- Handle extra edge case when detecting for socket readability when using `asyncio`. (Pull #242, #244) -- Fix `asyncio` SSL warning when using proxy tunneling. (Pull #249) - -## 0.12.2 (November 20th, 2020) - -### Fixed - -- Properly wrap connect errors on the asyncio backend. (Pull #235) -- Fix `ImportError` occurring on Python 3.9 when using the HTTP/1.1 sync client in a multithreaded context. (Pull #237) - -## 0.12.1 (November 7th, 2020) - -### Added - -- Add connect retries. (Pull #221) - -### Fixed - -- Tweak detection of dropped connections, resolving an issue with open files limits on Linux. (Pull #185) -- Avoid leaking connections when establishing an HTTP tunnel to a proxy has failed. (Pull #223) -- Properly wrap OS errors when using `trio`. (Pull #225) - -## 0.12.0 (October 6th, 2020) - -### Changed - -- HTTP header casing is now preserved, rather than always sent in lowercase. (#216 and python-hyper/h11#104) - -### Added - -- Add Python 3.9 to officially supported versions. - -### Fixed - -- Gracefully handle a stdlib asyncio bug when a connection is closed while it is in a paused-for-reading state. (#201) - -## 0.11.1 (September 28nd, 2020) - -### Fixed - -- Add await to async semaphore release() coroutine (#197) -- Drop incorrect curio classifier (#192) - -## 0.11.0 (September 22nd, 2020) - -The Transport API with 0.11.0 has a couple of significant changes. - -Firstly we've moved changed the request interface in order to allow extensions, which will later enable us to support features -such as trailing headers, HTTP/2 server push, and CONNECT/Upgrade connections. - -The interface changes from: - -```python -def request(method, url, headers, stream, timeout): - return (http_version, status_code, reason, headers, stream) -``` - -To instead including an optional dictionary of extensions on the request and response: - -```python -def request(method, url, headers, stream, ext): - return (status_code, headers, stream, ext) -``` - -Having an open-ended extensions point will allow us to add later support for various optional features, that wouldn't otherwise be supported without these API changes. - -In particular: - -* Trailing headers support. -* HTTP/2 Server Push -* sendfile. -* Exposing raw connection on CONNECT, Upgrade, HTTP/2 bi-di streaming. -* Exposing debug information out of the API, including template name, template context. - -Currently extensions are limited to: - -* request: `timeout` - Optional. Timeout dictionary. -* response: `http_version` - Optional. Include the HTTP version used on the response. -* response: `reason` - Optional. Include the reason phrase used on the response. Only valid with HTTP/1.*. - -See https://github.com/encode/httpx/issues/1274#issuecomment-694884553 for the history behind this. - -Secondly, the async version of `request` is now namespaced as `arequest`. - -This allows concrete transports to support both sync and async implementations on the same class. - -### Added - -- Add curio support. (Pull #168) -- Add anyio support, with `backend="anyio"`. (Pull #169) - -### Changed - -- Update the Transport API to use 'ext' for optional extensions. (Pull #190) -- Update the Transport API to use `.request` and `.arequest` so implementations can support both sync and async. (Pull #189) - -## 0.10.2 (August 20th, 2020) - -### Added - -- Added Unix Domain Socket support. (Pull #139) - -### Fixed - -- Always include the port on proxy CONNECT requests. (Pull #154) -- Fix `max_keepalive_connections` configuration. (Pull #153) -- Fixes behaviour in HTTP/1.1 where server disconnects can be used to signal the end of the response body. (Pull #164) - -## 0.10.1 (August 7th, 2020) - -- Include `max_keepalive_connections` on `AsyncHTTPProxy`/`SyncHTTPProxy` classes. - -## 0.10.0 (August 7th, 2020) - -The most notable change in the 0.10.0 release is that HTTP/2 support is now fully optional. - -Use either `pip install httpcore` for HTTP/1.1 support only, or `pip install httpcore[http2]` for HTTP/1.1 and HTTP/2 support. - -### Added - -- HTTP/2 support becomes optional. (Pull #121, #130) -- Add `local_address=...` support. (Pull #100, #134) -- Add `PlainByteStream`, `IteratorByteStream`, `AsyncIteratorByteStream`. The `AsyncByteSteam` and `SyncByteStream` classes are now pure interface classes. (#133) -- Add `LocalProtocolError`, `RemoteProtocolError` exceptions. (Pull #129) -- Add `UnsupportedProtocol` exception. (Pull #128) -- Add `.get_connection_info()` method. (Pull #102, #137) -- Add better TRACE logs. (Pull #101) - -### Changed - -- `max_keepalive` is deprecated in favour of `max_keepalive_connections`. (Pull #140) - -### Fixed - -- Improve handling of server disconnects. (Pull #112) - -## 0.9.1 (May 27th, 2020) - -### Fixed - -- Proper host resolution for sync case, including IPv6 support. (Pull #97) -- Close outstanding connections when connection pool is closed. (Pull #98) - -## 0.9.0 (May 21th, 2020) - -### Changed - -- URL port becomes an `Optional[int]` instead of `int`. (Pull #92) - -### Fixed - -- Honor HTTP/2 max concurrent streams settings. (Pull #89, #90) -- Remove incorrect debug log. (Pull #83) - -## 0.8.4 (May 11th, 2020) - -### Added - -- Logging via HTTPCORE_LOG_LEVEL and HTTPX_LOG_LEVEL environment variables -and TRACE level logging. (Pull #79) - -### Fixed - -- Reuse of connections on HTTP/2 in close concurrency situations. (Pull #81) - -## 0.8.3 (May 6rd, 2020) - -### Fixed - -- Include `Host` and `Accept` headers on proxy "CONNECT" requests. -- De-duplicate any headers also contained in proxy_headers. -- HTTP/2 flag not being passed down to proxy connections. - -## 0.8.2 (May 3rd, 2020) - -### Fixed - -- Fix connections using proxy forwarding requests not being added to the -connection pool properly. (Pull #70) - -## 0.8.1 (April 30th, 2020) - -### Changed - -- Allow inherintance of both `httpcore.AsyncByteStream`, `httpcore.SyncByteStream` without type conflicts. - -## 0.8.0 (April 30th, 2020) - -### Fixed - -- Fixed tunnel proxy support. - -### Added - -- New `TimeoutException` base class. - -## 0.7.0 (March 5th, 2020) - -- First integration with HTTPX. diff --git a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/RECORD b/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/RECORD deleted file mode 100644 index aac7c19612e1316861a77cb89aab09c6b1a0f1b2..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/RECORD +++ /dev/null @@ -1,68 +0,0 @@ -httpcore-1.0.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -httpcore-1.0.9.dist-info/METADATA,sha256=_i1P2mGZEol4d54M8n88BFxTGGP83Zh-rMdPOhjUHCE,21529 -httpcore-1.0.9.dist-info/RECORD,, -httpcore-1.0.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 -httpcore-1.0.9.dist-info/licenses/LICENSE.md,sha256=_ctZFUx0y6uhahEkL3dAvqnyPW_rVUeRfYxflKgDkqU,1518 -httpcore/__init__.py,sha256=9kT_kqChCCJUTHww24ZmR_ezcdbpRYWksD-gYNzkZP8,3445 -httpcore/__pycache__/__init__.cpython-310.pyc,, -httpcore/__pycache__/_api.cpython-310.pyc,, -httpcore/__pycache__/_exceptions.cpython-310.pyc,, -httpcore/__pycache__/_models.cpython-310.pyc,, -httpcore/__pycache__/_ssl.cpython-310.pyc,, -httpcore/__pycache__/_synchronization.cpython-310.pyc,, -httpcore/__pycache__/_trace.cpython-310.pyc,, -httpcore/__pycache__/_utils.cpython-310.pyc,, -httpcore/_api.py,sha256=unZmeDschBWCGCPCwkS3Wot9euK6bg_kKxLtGTxw214,3146 -httpcore/_async/__init__.py,sha256=EWdl2v4thnAHzJpqjU4h2a8DUiGAvNiWrkii9pfhTf0,1221 -httpcore/_async/__pycache__/__init__.cpython-310.pyc,, -httpcore/_async/__pycache__/connection.cpython-310.pyc,, -httpcore/_async/__pycache__/connection_pool.cpython-310.pyc,, -httpcore/_async/__pycache__/http11.cpython-310.pyc,, -httpcore/_async/__pycache__/http2.cpython-310.pyc,, -httpcore/_async/__pycache__/http_proxy.cpython-310.pyc,, -httpcore/_async/__pycache__/interfaces.cpython-310.pyc,, -httpcore/_async/__pycache__/socks_proxy.cpython-310.pyc,, -httpcore/_async/connection.py,sha256=6OcPXqMEfc0BU38_-iHUNDd1vKSTc2UVT09XqNb_BOk,8449 -httpcore/_async/connection_pool.py,sha256=DOIQ2s2ZCf9qfwxhzMprTPLqCL8OxGXiKF6qRHxvVyY,17307 -httpcore/_async/http11.py,sha256=-qM9bV7PjSQF5vxs37-eUXOIFwbIjPcZbNliuX9TtBw,13880 -httpcore/_async/http2.py,sha256=azX1fcmtXaIwjputFlZ4vd92J8xwjGOa9ax9QIv4394,23936 -httpcore/_async/http_proxy.py,sha256=2zVkrlv-Ds-rWGaqaXlrhEJiAQFPo23BT3Gq_sWoBXU,14701 -httpcore/_async/interfaces.py,sha256=jTiaWL83pgpGC9ziv90ZfwaKNMmHwmOalzaKiuTxATo,4455 -httpcore/_async/socks_proxy.py,sha256=lLKgLlggPfhFlqi0ODeBkOWvt9CghBBUyqsnsU1tx6Q,13841 -httpcore/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -httpcore/_backends/__pycache__/__init__.cpython-310.pyc,, -httpcore/_backends/__pycache__/anyio.cpython-310.pyc,, -httpcore/_backends/__pycache__/auto.cpython-310.pyc,, -httpcore/_backends/__pycache__/base.cpython-310.pyc,, -httpcore/_backends/__pycache__/mock.cpython-310.pyc,, -httpcore/_backends/__pycache__/sync.cpython-310.pyc,, -httpcore/_backends/__pycache__/trio.cpython-310.pyc,, -httpcore/_backends/anyio.py,sha256=x8PgEhXRC8bVqsdzk_YJx8Y6d9Tub06CuUSwnbmtqoY,5252 -httpcore/_backends/auto.py,sha256=zO136PKZmsaTDK-HRk84eA-MUg8_2wJf4NvmK432Aio,1662 -httpcore/_backends/base.py,sha256=aShgRdZnMmRhFWHetjumlM73f8Kz1YOAyCUP_4kHslA,3042 -httpcore/_backends/mock.py,sha256=er9T436uSe7NLrfiLa4x6Nuqg5ivQ693CxWYCWsgbH4,4077 -httpcore/_backends/sync.py,sha256=bhE4d9iK9Umxdsdsgm2EfKnXaBms2WggGYU-7jmUujU,7977 -httpcore/_backends/trio.py,sha256=LHu4_Mr5MswQmmT3yE4oLgf9b_JJfeVS4BjDxeJc7Ro,5996 -httpcore/_exceptions.py,sha256=looCKga3_YVYu3s-d3L9RMPRJyhsY7fiuuGxvkOD0c0,1184 -httpcore/_models.py,sha256=IO2CcXcdpovRcLTdGFGB6RyBZdEm2h_TOmoCc4rEKho,17623 -httpcore/_ssl.py,sha256=srqmSNU4iOUvWF-SrJvb8G_YEbHFELOXQOwdDIBTS9c,187 -httpcore/_sync/__init__.py,sha256=JBDIgXt5la1LCJ1sLQeKhjKFpLnpNr8Svs6z2ni3fgg,1141 -httpcore/_sync/__pycache__/__init__.cpython-310.pyc,, -httpcore/_sync/__pycache__/connection.cpython-310.pyc,, -httpcore/_sync/__pycache__/connection_pool.cpython-310.pyc,, -httpcore/_sync/__pycache__/http11.cpython-310.pyc,, -httpcore/_sync/__pycache__/http2.cpython-310.pyc,, -httpcore/_sync/__pycache__/http_proxy.cpython-310.pyc,, -httpcore/_sync/__pycache__/interfaces.cpython-310.pyc,, -httpcore/_sync/__pycache__/socks_proxy.cpython-310.pyc,, -httpcore/_sync/connection.py,sha256=9exGOb3PB-Mp2T1-sckSeL2t-tJ_9-NXomV8ihmWCgU,8238 -httpcore/_sync/connection_pool.py,sha256=a-T8LTsUxc7r0Ww1atfHSDoWPjQ0fA8Ul7S3-F0Mj70,16955 -httpcore/_sync/http11.py,sha256=IFobD1Md5JFlJGKWnh1_Q3epikUryI8qo09v8MiJIEA,13476 -httpcore/_sync/http2.py,sha256=AxU4yhcq68Bn5vqdJYtiXKYUj7nvhYbxz3v4rT4xnvA,23400 -httpcore/_sync/http_proxy.py,sha256=_al_6crKuEZu2wyvu493RZImJdBJnj5oGKNjLOJL2Zo,14463 -httpcore/_sync/interfaces.py,sha256=snXON42vUDHO5JBJvo8D4VWk2Wat44z2OXXHDrjbl94,4344 -httpcore/_sync/socks_proxy.py,sha256=zegZW9Snqj2_992DFJa8_CppOVBkVL4AgwduRkStakQ,13614 -httpcore/_synchronization.py,sha256=zSi13mAColBnknjZBknUC6hKNDQT4C6ijnezZ-r0T2s,9434 -httpcore/_trace.py,sha256=ck6ZoIzYTkdNAIfq5MGeKqBXDtqjOX-qfYwmZFbrGco,3952 -httpcore/_utils.py,sha256=_RLgXYOAYC350ikALV59GZ68IJrdocRZxPs9PjmzdFY,1537 -httpcore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/WHEEL b/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/WHEEL deleted file mode 100644 index 12228d414b6cfed7c39d3781c85c63256a1d7fb5..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.27.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE.md b/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE.md deleted file mode 100644 index 311b2b56c53f678ab95fc0def708c675d521a807..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE.md +++ /dev/null @@ -1,27 +0,0 @@ -Copyright © 2020, [Encode OSS Ltd](https://www.encode.io/). -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.10/site-packages/httpcore/__init__.py b/venv/lib/python3.10/site-packages/httpcore/__init__.py deleted file mode 100644 index 9a92dc4a440bdf6f259ec1083c89c817eb7b631b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/__init__.py +++ /dev/null @@ -1,141 +0,0 @@ -from ._api import request, stream -from ._async import ( - AsyncConnectionInterface, - AsyncConnectionPool, - AsyncHTTP2Connection, - AsyncHTTP11Connection, - AsyncHTTPConnection, - AsyncHTTPProxy, - AsyncSOCKSProxy, -) -from ._backends.base import ( - SOCKET_OPTION, - AsyncNetworkBackend, - AsyncNetworkStream, - NetworkBackend, - NetworkStream, -) -from ._backends.mock import AsyncMockBackend, AsyncMockStream, MockBackend, MockStream -from ._backends.sync import SyncBackend -from ._exceptions import ( - ConnectError, - ConnectionNotAvailable, - ConnectTimeout, - LocalProtocolError, - NetworkError, - PoolTimeout, - ProtocolError, - ProxyError, - ReadError, - ReadTimeout, - RemoteProtocolError, - TimeoutException, - UnsupportedProtocol, - WriteError, - WriteTimeout, -) -from ._models import URL, Origin, Proxy, Request, Response -from ._ssl import default_ssl_context -from ._sync import ( - ConnectionInterface, - ConnectionPool, - HTTP2Connection, - HTTP11Connection, - HTTPConnection, - HTTPProxy, - SOCKSProxy, -) - -# The 'httpcore.AnyIOBackend' class is conditional on 'anyio' being installed. -try: - from ._backends.anyio import AnyIOBackend -except ImportError: # pragma: nocover - - class AnyIOBackend: # type: ignore - def __init__(self, *args, **kwargs): # type: ignore - msg = ( - "Attempted to use 'httpcore.AnyIOBackend' but 'anyio' is not installed." - ) - raise RuntimeError(msg) - - -# The 'httpcore.TrioBackend' class is conditional on 'trio' being installed. -try: - from ._backends.trio import TrioBackend -except ImportError: # pragma: nocover - - class TrioBackend: # type: ignore - def __init__(self, *args, **kwargs): # type: ignore - msg = "Attempted to use 'httpcore.TrioBackend' but 'trio' is not installed." - raise RuntimeError(msg) - - -__all__ = [ - # top-level requests - "request", - "stream", - # models - "Origin", - "URL", - "Request", - "Response", - "Proxy", - # async - "AsyncHTTPConnection", - "AsyncConnectionPool", - "AsyncHTTPProxy", - "AsyncHTTP11Connection", - "AsyncHTTP2Connection", - "AsyncConnectionInterface", - "AsyncSOCKSProxy", - # sync - "HTTPConnection", - "ConnectionPool", - "HTTPProxy", - "HTTP11Connection", - "HTTP2Connection", - "ConnectionInterface", - "SOCKSProxy", - # network backends, implementations - "SyncBackend", - "AnyIOBackend", - "TrioBackend", - # network backends, mock implementations - "AsyncMockBackend", - "AsyncMockStream", - "MockBackend", - "MockStream", - # network backends, interface - "AsyncNetworkStream", - "AsyncNetworkBackend", - "NetworkStream", - "NetworkBackend", - # util - "default_ssl_context", - "SOCKET_OPTION", - # exceptions - "ConnectionNotAvailable", - "ProxyError", - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", - "UnsupportedProtocol", - "TimeoutException", - "PoolTimeout", - "ConnectTimeout", - "ReadTimeout", - "WriteTimeout", - "NetworkError", - "ConnectError", - "ReadError", - "WriteError", -] - -__version__ = "1.0.9" - - -__locals = locals() -for __name in __all__: - # Exclude SOCKET_OPTION, it causes AttributeError on Python 3.14 - if not __name.startswith(("__", "SOCKET_OPTION")): - setattr(__locals[__name], "__module__", "httpcore") # noqa diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index ce8f7f9d5185b5fc047b3419df015a299f0b632d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_api.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/_api.cpython-310.pyc deleted file mode 100644 index 08644c01ab7f609acf7e3ce7b3f543cbe6e475b1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_api.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_exceptions.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/_exceptions.cpython-310.pyc deleted file mode 100644 index 9c1283371ed56c4f4ac9508e976fe89bbe446ae1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_exceptions.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_models.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/_models.cpython-310.pyc deleted file mode 100644 index d76c5440be65487b3d87960b2195776f978473c5..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_models.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_ssl.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/_ssl.cpython-310.pyc deleted file mode 100644 index 2fb8e080754dfb1014c33531243b2319f92cc953..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_ssl.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_synchronization.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/_synchronization.cpython-310.pyc deleted file mode 100644 index 9bf604efd292523fe150f1e13e90855d8839f6b5..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_synchronization.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_trace.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/_trace.cpython-310.pyc deleted file mode 100644 index d9583ca3612821e2dfb1c61d48a22b9600d118ab..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_trace.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_utils.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/__pycache__/_utils.cpython-310.pyc deleted file mode 100644 index 8f9cf95cd87a93c53b311a9362adce1dbc99931b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/__pycache__/_utils.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_api.py b/venv/lib/python3.10/site-packages/httpcore/_api.py deleted file mode 100644 index 38b961d10de88bebc98c758d0d1f14af1e7c0370..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_api.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import annotations - -import contextlib -import typing - -from ._models import URL, Extensions, HeaderTypes, Response -from ._sync.connection_pool import ConnectionPool - - -def request( - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, -) -> Response: - """ - Sends an HTTP request, returning the response. - - ``` - response = httpcore.request("GET", "https://www.example.com/") - ``` - - Arguments: - method: The HTTP method for the request. Typically one of `"GET"`, - `"OPTIONS"`, `"HEAD"`, `"POST"`, `"PUT"`, `"PATCH"`, or `"DELETE"`. - url: The URL of the HTTP request. Either as an instance of `httpcore.URL`, - or as str/bytes. - headers: The HTTP request headers. Either as a dictionary of str/bytes, - or as a list of two-tuples of str/bytes. - content: The content of the request body. Either as bytes, - or as a bytes iterator. - extensions: A dictionary of optional extra information included on the request. - Possible keys include `"timeout"`. - - Returns: - An instance of `httpcore.Response`. - """ - with ConnectionPool() as pool: - return pool.request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - - -@contextlib.contextmanager -def stream( - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, -) -> typing.Iterator[Response]: - """ - Sends an HTTP request, returning the response within a content manager. - - ``` - with httpcore.stream("GET", "https://www.example.com/") as response: - ... - ``` - - When using the `stream()` function, the body of the response will not be - automatically read. If you want to access the response body you should - either use `content = response.read()`, or `for chunk in response.iter_content()`. - - Arguments: - method: The HTTP method for the request. Typically one of `"GET"`, - `"OPTIONS"`, `"HEAD"`, `"POST"`, `"PUT"`, `"PATCH"`, or `"DELETE"`. - url: The URL of the HTTP request. Either as an instance of `httpcore.URL`, - or as str/bytes. - headers: The HTTP request headers. Either as a dictionary of str/bytes, - or as a list of two-tuples of str/bytes. - content: The content of the request body. Either as bytes, - or as a bytes iterator. - extensions: A dictionary of optional extra information included on the request. - Possible keys include `"timeout"`. - - Returns: - An instance of `httpcore.Response`. - """ - with ConnectionPool() as pool: - with pool.stream( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) as response: - yield response diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__init__.py b/venv/lib/python3.10/site-packages/httpcore/_async/__init__.py deleted file mode 100644 index 88dc7f01e132933728cbcf45c88ce82e85ddf65f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -from .connection import AsyncHTTPConnection -from .connection_pool import AsyncConnectionPool -from .http11 import AsyncHTTP11Connection -from .http_proxy import AsyncHTTPProxy -from .interfaces import AsyncConnectionInterface - -try: - from .http2 import AsyncHTTP2Connection -except ImportError: # pragma: nocover - - class AsyncHTTP2Connection: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use http2 support, but the `h2` package is not " - "installed. Use 'pip install httpcore[http2]'." - ) - - -try: - from .socks_proxy import AsyncSOCKSProxy -except ImportError: # pragma: nocover - - class AsyncSOCKSProxy: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use SOCKS support, but the `socksio` package is not " - "installed. Use 'pip install httpcore[socks]'." - ) - - -__all__ = [ - "AsyncHTTPConnection", - "AsyncConnectionPool", - "AsyncHTTPProxy", - "AsyncHTTP11Connection", - "AsyncHTTP2Connection", - "AsyncConnectionInterface", - "AsyncSOCKSProxy", -] diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index aeb8f3857ee8b3c930a10663073ea7d6536131e5..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/connection.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/connection.cpython-310.pyc deleted file mode 100644 index 6a16afa783e6bb6436e35c30d83ad78418215f5b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/connection.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/connection_pool.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/connection_pool.cpython-310.pyc deleted file mode 100644 index fb49662e0fa07377f5a320a8e02a54ef3219b16f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/connection_pool.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http11.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http11.cpython-310.pyc deleted file mode 100644 index a70bac2c4e8bceea591ccd327c81726f4b969862..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http11.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http2.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http2.cpython-310.pyc deleted file mode 100644 index b1a54516d8efd602432c2f9ce1d56d472c1ab0a4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http2.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http_proxy.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http_proxy.cpython-310.pyc deleted file mode 100644 index c78e4f956dae8cf1702f64d7a60e988cbd3593e4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/http_proxy.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/interfaces.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/interfaces.cpython-310.pyc deleted file mode 100644 index 194f2f34c5484f55348e15d721152281dd9179e0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/interfaces.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/socks_proxy.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/socks_proxy.cpython-310.pyc deleted file mode 100644 index 22b7a74671946f397fe6a7eb3aa01cfd8166f8dc..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_async/__pycache__/socks_proxy.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/connection.py b/venv/lib/python3.10/site-packages/httpcore/_async/connection.py deleted file mode 100644 index b42581dff8aabf4c2ef80ffda26296e1b368d693..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/connection.py +++ /dev/null @@ -1,222 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -import ssl -import types -import typing - -from .._backends.auto import AutoBackend -from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream -from .._exceptions import ConnectError, ConnectTimeout -from .._models import Origin, Request, Response -from .._ssl import default_ssl_context -from .._synchronization import AsyncLock -from .._trace import Trace -from .http11 import AsyncHTTP11Connection -from .interfaces import AsyncConnectionInterface - -RETRIES_BACKOFF_FACTOR = 0.5 # 0s, 0.5s, 1s, 2s, 4s, etc. - - -logger = logging.getLogger("httpcore.connection") - - -def exponential_backoff(factor: float) -> typing.Iterator[float]: - """ - Generate a geometric sequence that has a ratio of 2 and starts with 0. - - For example: - - `factor = 2`: `0, 2, 4, 8, 16, 32, 64, ...` - - `factor = 3`: `0, 3, 6, 12, 24, 48, 96, ...` - """ - yield 0 - for n in itertools.count(): - yield factor * 2**n - - -class AsyncHTTPConnection(AsyncConnectionInterface): - def __init__( - self, - origin: Origin, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._origin = origin - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend: AsyncNetworkBackend = ( - AutoBackend() if network_backend is None else network_backend - ) - self._connection: AsyncConnectionInterface | None = None - self._connect_failed: bool = False - self._request_lock = AsyncLock() - self._socket_options = socket_options - - async def handle_async_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection to {self._origin}" - ) - - try: - async with self._request_lock: - if self._connection is None: - stream = await self._connect(request) - - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import AsyncHTTP2Connection - - self._connection = AsyncHTTP2Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = AsyncHTTP11Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except BaseException as exc: - self._connect_failed = True - raise exc - - return await self._connection.handle_async_request(request) - - async def _connect(self, request: Request) -> AsyncNetworkStream: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - retries_left = self._retries - delays = exponential_backoff(factor=RETRIES_BACKOFF_FACTOR) - - while True: - try: - if self._uds is None: - kwargs = { - "host": self._origin.host.decode("ascii"), - "port": self._origin.port, - "local_address": self._local_address, - "timeout": timeout, - "socket_options": self._socket_options, - } - async with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = await self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - else: - kwargs = { - "path": self._uds, - "timeout": timeout, - "socket_options": self._socket_options, - } - async with Trace( - "connect_unix_socket", logger, request, kwargs - ) as trace: - stream = await self._network_backend.connect_unix_socket( - **kwargs - ) - trace.return_value = stream - - if self._origin.scheme in (b"https", b"wss"): - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._origin.host.decode("ascii"), - "timeout": timeout, - } - async with Trace("start_tls", logger, request, kwargs) as trace: - stream = await stream.start_tls(**kwargs) - trace.return_value = stream - return stream - except (ConnectError, ConnectTimeout): - if retries_left <= 0: - raise - retries_left -= 1 - delay = next(delays) - async with Trace("retry", logger, request, kwargs) as trace: - await self._network_backend.sleep(delay) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - async def aclose(self) -> None: - if self._connection is not None: - async with Trace("close", logger, None, {}): - await self._connection.aclose() - - def is_available(self) -> bool: - if self._connection is None: - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - async def __aenter__(self) -> AsyncHTTPConnection: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/connection_pool.py b/venv/lib/python3.10/site-packages/httpcore/_async/connection_pool.py deleted file mode 100644 index 96e973d0ce223f6bed9be9e6a6a2f3c01622c611..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/connection_pool.py +++ /dev/null @@ -1,420 +0,0 @@ -from __future__ import annotations - -import ssl -import sys -import types -import typing - -from .._backends.auto import AutoBackend -from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend -from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol -from .._models import Origin, Proxy, Request, Response -from .._synchronization import AsyncEvent, AsyncShieldCancellation, AsyncThreadLock -from .connection import AsyncHTTPConnection -from .interfaces import AsyncConnectionInterface, AsyncRequestInterface - - -class AsyncPoolRequest: - def __init__(self, request: Request) -> None: - self.request = request - self.connection: AsyncConnectionInterface | None = None - self._connection_acquired = AsyncEvent() - - def assign_to_connection(self, connection: AsyncConnectionInterface | None) -> None: - self.connection = connection - self._connection_acquired.set() - - def clear_connection(self) -> None: - self.connection = None - self._connection_acquired = AsyncEvent() - - async def wait_for_connection( - self, timeout: float | None = None - ) -> AsyncConnectionInterface: - if self.connection is None: - await self._connection_acquired.wait(timeout=timeout) - assert self.connection is not None - return self.connection - - def is_queued(self) -> bool: - return self.connection is None - - -class AsyncConnectionPool(AsyncRequestInterface): - """ - A connection pool for making HTTP requests. - """ - - def __init__( - self, - ssl_context: ssl.SSLContext | None = None, - proxy: Proxy | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish a - connection. - local_address: Local address to connect from. Can also be used to connect - using a particular address family. Using `local_address="0.0.0.0"` - will connect using an `AF_INET` address (IPv4), while using - `local_address="::"` will connect using an `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - socket_options: Socket options that have to be included - in the TCP socket when the connection was established. - """ - self._ssl_context = ssl_context - self._proxy = proxy - self._max_connections = ( - sys.maxsize if max_connections is None else max_connections - ) - self._max_keepalive_connections = ( - sys.maxsize - if max_keepalive_connections is None - else max_keepalive_connections - ) - self._max_keepalive_connections = min( - self._max_connections, self._max_keepalive_connections - ) - - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend = ( - AutoBackend() if network_backend is None else network_backend - ) - self._socket_options = socket_options - - # The mutable state on a connection pool is the queue of incoming requests, - # and the set of connections that are servicing those requests. - self._connections: list[AsyncConnectionInterface] = [] - self._requests: list[AsyncPoolRequest] = [] - - # We only mutate the state of the connection pool within an 'optional_thread_lock' - # context. This holds a threading lock unless we're running in async mode, - # in which case it is a no-op. - self._optional_thread_lock = AsyncThreadLock() - - def create_connection(self, origin: Origin) -> AsyncConnectionInterface: - if self._proxy is not None: - if self._proxy.url.scheme in (b"socks5", b"socks5h"): - from .socks_proxy import AsyncSocks5Connection - - return AsyncSocks5Connection( - proxy_origin=self._proxy.url.origin, - proxy_auth=self._proxy.auth, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - elif origin.scheme == b"http": - from .http_proxy import AsyncForwardHTTPConnection - - return AsyncForwardHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - ) - from .http_proxy import AsyncTunnelHTTPConnection - - return AsyncTunnelHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - return AsyncHTTPConnection( - origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - retries=self._retries, - local_address=self._local_address, - uds=self._uds, - network_backend=self._network_backend, - socket_options=self._socket_options, - ) - - @property - def connections(self) -> list[AsyncConnectionInterface]: - """ - Return a list of the connections currently in the pool. - - For example: - - ```python - >>> pool.connections - [ - , - , - , - ] - ``` - """ - return list(self._connections) - - async def handle_async_request(self, request: Request) -> Response: - """ - Send an HTTP request, and return an HTTP response. - - This is the core implementation that is called into by `.request()` or `.stream()`. - """ - scheme = request.url.scheme.decode() - if scheme == "": - raise UnsupportedProtocol( - "Request URL is missing an 'http://' or 'https://' protocol." - ) - if scheme not in ("http", "https", "ws", "wss"): - raise UnsupportedProtocol( - f"Request URL has an unsupported protocol '{scheme}://'." - ) - - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("pool", None) - - with self._optional_thread_lock: - # Add the incoming request to our request queue. - pool_request = AsyncPoolRequest(request) - self._requests.append(pool_request) - - try: - while True: - with self._optional_thread_lock: - # Assign incoming requests to available connections, - # closing or creating new connections as required. - closing = self._assign_requests_to_connections() - await self._close_connections(closing) - - # Wait until this request has an assigned connection. - connection = await pool_request.wait_for_connection(timeout=timeout) - - try: - # Send the request on the assigned connection. - response = await connection.handle_async_request( - pool_request.request - ) - except ConnectionNotAvailable: - # In some cases a connection may initially be available to - # handle a request, but then become unavailable. - # - # In this case we clear the connection and try again. - pool_request.clear_connection() - else: - break # pragma: nocover - - except BaseException as exc: - with self._optional_thread_lock: - # For any exception or cancellation we remove the request from - # the queue, and then re-assign requests to connections. - self._requests.remove(pool_request) - closing = self._assign_requests_to_connections() - - await self._close_connections(closing) - raise exc from None - - # Return the response. Note that in this case we still have to manage - # the point at which the response is closed. - assert isinstance(response.stream, typing.AsyncIterable) - return Response( - status=response.status, - headers=response.headers, - content=PoolByteStream( - stream=response.stream, pool_request=pool_request, pool=self - ), - extensions=response.extensions, - ) - - def _assign_requests_to_connections(self) -> list[AsyncConnectionInterface]: - """ - Manage the state of the connection pool, assigning incoming - requests to connections as available. - - Called whenever a new request is added or removed from the pool. - - Any closing connections are returned, allowing the I/O for closing - those connections to be handled seperately. - """ - closing_connections = [] - - # First we handle cleaning up any connections that are closed, - # have expired their keep-alive, or surplus idle connections. - for connection in list(self._connections): - if connection.is_closed(): - # log: "removing closed connection" - self._connections.remove(connection) - elif connection.has_expired(): - # log: "closing expired connection" - self._connections.remove(connection) - closing_connections.append(connection) - elif ( - connection.is_idle() - and len([connection.is_idle() for connection in self._connections]) - > self._max_keepalive_connections - ): - # log: "closing idle connection" - self._connections.remove(connection) - closing_connections.append(connection) - - # Assign queued requests to connections. - queued_requests = [request for request in self._requests if request.is_queued()] - for pool_request in queued_requests: - origin = pool_request.request.url.origin - available_connections = [ - connection - for connection in self._connections - if connection.can_handle_request(origin) and connection.is_available() - ] - idle_connections = [ - connection for connection in self._connections if connection.is_idle() - ] - - # There are three cases for how we may be able to handle the request: - # - # 1. There is an existing connection that can handle the request. - # 2. We can create a new connection to handle the request. - # 3. We can close an idle connection and then create a new connection - # to handle the request. - if available_connections: - # log: "reusing existing connection" - connection = available_connections[0] - pool_request.assign_to_connection(connection) - elif len(self._connections) < self._max_connections: - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - elif idle_connections: - # log: "closing idle connection" - connection = idle_connections[0] - self._connections.remove(connection) - closing_connections.append(connection) - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - - return closing_connections - - async def _close_connections(self, closing: list[AsyncConnectionInterface]) -> None: - # Close connections which have been removed from the pool. - with AsyncShieldCancellation(): - for connection in closing: - await connection.aclose() - - async def aclose(self) -> None: - # Explicitly close the connection pool. - # Clears all existing requests and connections. - with self._optional_thread_lock: - closing_connections = list(self._connections) - self._connections = [] - await self._close_connections(closing_connections) - - async def __aenter__(self) -> AsyncConnectionPool: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - with self._optional_thread_lock: - request_is_queued = [request.is_queued() for request in self._requests] - connection_is_idle = [ - connection.is_idle() for connection in self._connections - ] - - num_active_requests = request_is_queued.count(False) - num_queued_requests = request_is_queued.count(True) - num_active_connections = connection_is_idle.count(False) - num_idle_connections = connection_is_idle.count(True) - - requests_info = ( - f"Requests: {num_active_requests} active, {num_queued_requests} queued" - ) - connection_info = ( - f"Connections: {num_active_connections} active, {num_idle_connections} idle" - ) - - return f"<{class_name} [{requests_info} | {connection_info}]>" - - -class PoolByteStream: - def __init__( - self, - stream: typing.AsyncIterable[bytes], - pool_request: AsyncPoolRequest, - pool: AsyncConnectionPool, - ) -> None: - self._stream = stream - self._pool_request = pool_request - self._pool = pool - self._closed = False - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - try: - async for part in self._stream: - yield part - except BaseException as exc: - await self.aclose() - raise exc from None - - async def aclose(self) -> None: - if not self._closed: - self._closed = True - with AsyncShieldCancellation(): - if hasattr(self._stream, "aclose"): - await self._stream.aclose() - - with self._pool._optional_thread_lock: - self._pool._requests.remove(self._pool_request) - closing = self._pool._assign_requests_to_connections() - - await self._pool._close_connections(closing) diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/http11.py b/venv/lib/python3.10/site-packages/httpcore/_async/http11.py deleted file mode 100644 index e6d6d709852b137a862cfe2b3af42dc790fa705d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/http11.py +++ /dev/null @@ -1,379 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import ssl -import time -import types -import typing - -import h11 - -from .._backends.base import AsyncNetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, - WriteError, - map_exceptions, -) -from .._models import Origin, Request, Response -from .._synchronization import AsyncLock, AsyncShieldCancellation -from .._trace import Trace -from .interfaces import AsyncConnectionInterface - -logger = logging.getLogger("httpcore.http11") - - -# A subset of `h11.Event` types supported by `_send_event` -H11SendEvent = typing.Union[ - h11.Request, - h11.Data, - h11.EndOfMessage, -] - - -class HTTPConnectionState(enum.IntEnum): - NEW = 0 - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class AsyncHTTP11Connection(AsyncConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - MAX_INCOMPLETE_EVENT_SIZE = 100 * 1024 - - def __init__( - self, - origin: Origin, - stream: AsyncNetworkStream, - keepalive_expiry: float | None = None, - ) -> None: - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._expire_at: float | None = None - self._state = HTTPConnectionState.NEW - self._state_lock = AsyncLock() - self._request_count = 0 - self._h11_state = h11.Connection( - our_role=h11.CLIENT, - max_incomplete_event_size=self.MAX_INCOMPLETE_EVENT_SIZE, - ) - - async def handle_async_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - async with self._state_lock: - if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): - self._request_count += 1 - self._state = HTTPConnectionState.ACTIVE - self._expire_at = None - else: - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request} - try: - async with Trace( - "send_request_headers", logger, request, kwargs - ) as trace: - await self._send_request_headers(**kwargs) - async with Trace("send_request_body", logger, request, kwargs) as trace: - await self._send_request_body(**kwargs) - except WriteError: - # If we get a write error while we're writing the request, - # then we supress this error and move on to attempting to - # read the response. Servers can sometimes close the request - # pre-emptively and then respond with a well formed HTTP - # error response. - pass - - async with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - ( - http_version, - status, - reason_phrase, - headers, - trailing_data, - ) = await self._receive_response_headers(**kwargs) - trace.return_value = ( - http_version, - status, - reason_phrase, - headers, - ) - - network_stream = self._network_stream - - # CONNECT or Upgrade request - if (status == 101) or ( - (request.method == b"CONNECT") and (200 <= status < 300) - ): - network_stream = AsyncHTTP11UpgradeStream(network_stream, trailing_data) - - return Response( - status=status, - headers=headers, - content=HTTP11ConnectionByteStream(self, request), - extensions={ - "http_version": http_version, - "reason_phrase": reason_phrase, - "network_stream": network_stream, - }, - ) - except BaseException as exc: - with AsyncShieldCancellation(): - async with Trace("response_closed", logger, request) as trace: - await self._response_closed() - raise exc - - # Sending the request... - - async def _send_request_headers(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - with map_exceptions({h11.LocalProtocolError: LocalProtocolError}): - event = h11.Request( - method=request.method, - target=request.url.target, - headers=request.headers, - ) - await self._send_event(event, timeout=timeout) - - async def _send_request_body(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - assert isinstance(request.stream, typing.AsyncIterable) - async for chunk in request.stream: - event = h11.Data(data=chunk) - await self._send_event(event, timeout=timeout) - - await self._send_event(h11.EndOfMessage(), timeout=timeout) - - async def _send_event(self, event: h11.Event, timeout: float | None = None) -> None: - bytes_to_send = self._h11_state.send(event) - if bytes_to_send is not None: - await self._network_stream.write(bytes_to_send, timeout=timeout) - - # Receiving the response... - - async def _receive_response_headers( - self, request: Request - ) -> tuple[bytes, int, bytes, list[tuple[bytes, bytes]], bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = await self._receive_event(timeout=timeout) - if isinstance(event, h11.Response): - break - if ( - isinstance(event, h11.InformationalResponse) - and event.status_code == 101 - ): - break - - http_version = b"HTTP/" + event.http_version - - # h11 version 0.11+ supports a `raw_items` interface to get the - # raw header casing, rather than the enforced lowercase headers. - headers = event.headers.raw_items() - - trailing_data, _ = self._h11_state.trailing_data - - return http_version, event.status_code, event.reason, headers, trailing_data - - async def _receive_response_body( - self, request: Request - ) -> typing.AsyncIterator[bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = await self._receive_event(timeout=timeout) - if isinstance(event, h11.Data): - yield bytes(event.data) - elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): - break - - async def _receive_event( - self, timeout: float | None = None - ) -> h11.Event | type[h11.PAUSED]: - while True: - with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): - event = self._h11_state.next_event() - - if event is h11.NEED_DATA: - data = await self._network_stream.read( - self.READ_NUM_BYTES, timeout=timeout - ) - - # If we feed this case through h11 we'll raise an exception like: - # - # httpcore.RemoteProtocolError: can't handle event type - # ConnectionClosed when role=SERVER and state=SEND_RESPONSE - # - # Which is accurate, but not very informative from an end-user - # perspective. Instead we handle this case distinctly and treat - # it as a ConnectError. - if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: - msg = "Server disconnected without sending a response." - raise RemoteProtocolError(msg) - - self._h11_state.receive_data(data) - else: - # mypy fails to narrow the type in the above if statement above - return event # type: ignore[return-value] - - async def _response_closed(self) -> None: - async with self._state_lock: - if ( - self._h11_state.our_state is h11.DONE - and self._h11_state.their_state is h11.DONE - ): - self._state = HTTPConnectionState.IDLE - self._h11_state.start_next_cycle() - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - else: - await self.aclose() - - # Once the connection is no longer required... - - async def aclose(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._state = HTTPConnectionState.CLOSED - await self._network_stream.aclose() - - # The AsyncConnectionInterface methods provide information about the state of - # the connection, allowing for a connection pooling implementation to - # determine when to reuse and when to close the connection... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - # Note that HTTP/1.1 connections in the "NEW" state are not treated as - # being "available". The control flow which created the connection will - # be able to send an outgoing request, but the connection will not be - # acquired from the connection pool for any other request. - return self._state == HTTPConnectionState.IDLE - - def has_expired(self) -> bool: - now = time.monotonic() - keepalive_expired = self._expire_at is not None and now > self._expire_at - - # If the HTTP connection is idle but the socket is readable, then the - # only valid state is that the socket is about to return b"", indicating - # a server-initiated disconnect. - server_disconnected = ( - self._state == HTTPConnectionState.IDLE - and self._network_stream.get_extra_info("is_readable") - ) - - return keepalive_expired or server_disconnected - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/1.1, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - async def __aenter__(self) -> AsyncHTTP11Connection: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() - - -class HTTP11ConnectionByteStream: - def __init__(self, connection: AsyncHTTP11Connection, request: Request) -> None: - self._connection = connection - self._request = request - self._closed = False - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - kwargs = {"request": self._request} - try: - async with Trace("receive_response_body", logger, self._request, kwargs): - async for chunk in self._connection._receive_response_body(**kwargs): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with AsyncShieldCancellation(): - await self.aclose() - raise exc - - async def aclose(self) -> None: - if not self._closed: - self._closed = True - async with Trace("response_closed", logger, self._request): - await self._connection._response_closed() - - -class AsyncHTTP11UpgradeStream(AsyncNetworkStream): - def __init__(self, stream: AsyncNetworkStream, leading_data: bytes) -> None: - self._stream = stream - self._leading_data = leading_data - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._leading_data: - buffer = self._leading_data[:max_bytes] - self._leading_data = self._leading_data[max_bytes:] - return buffer - else: - return await self._stream.read(max_bytes, timeout) - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - await self._stream.write(buffer, timeout) - - async def aclose(self) -> None: - await self._stream.aclose() - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - return await self._stream.start_tls(ssl_context, server_hostname, timeout) - - def get_extra_info(self, info: str) -> typing.Any: - return self._stream.get_extra_info(info) diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/http2.py b/venv/lib/python3.10/site-packages/httpcore/_async/http2.py deleted file mode 100644 index dbd0beeb4da32d8c0175d412fa442eae8f837723..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/http2.py +++ /dev/null @@ -1,592 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import time -import types -import typing - -import h2.config -import h2.connection -import h2.events -import h2.exceptions -import h2.settings - -from .._backends.base import AsyncNetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, -) -from .._models import Origin, Request, Response -from .._synchronization import AsyncLock, AsyncSemaphore, AsyncShieldCancellation -from .._trace import Trace -from .interfaces import AsyncConnectionInterface - -logger = logging.getLogger("httpcore.http2") - - -def has_body_headers(request: Request) -> bool: - return any( - k.lower() == b"content-length" or k.lower() == b"transfer-encoding" - for k, v in request.headers - ) - - -class HTTPConnectionState(enum.IntEnum): - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class AsyncHTTP2Connection(AsyncConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - CONFIG = h2.config.H2Configuration(validate_inbound_headers=False) - - def __init__( - self, - origin: Origin, - stream: AsyncNetworkStream, - keepalive_expiry: float | None = None, - ): - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._h2_state = h2.connection.H2Connection(config=self.CONFIG) - self._state = HTTPConnectionState.IDLE - self._expire_at: float | None = None - self._request_count = 0 - self._init_lock = AsyncLock() - self._state_lock = AsyncLock() - self._read_lock = AsyncLock() - self._write_lock = AsyncLock() - self._sent_connection_init = False - self._used_all_stream_ids = False - self._connection_error = False - - # Mapping from stream ID to response stream events. - self._events: dict[ - int, - list[ - h2.events.ResponseReceived - | h2.events.DataReceived - | h2.events.StreamEnded - | h2.events.StreamReset, - ], - ] = {} - - # Connection terminated events are stored as state since - # we need to handle them for all streams. - self._connection_terminated: h2.events.ConnectionTerminated | None = None - - self._read_exception: Exception | None = None - self._write_exception: Exception | None = None - - async def handle_async_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - # This cannot occur in normal operation, since the connection pool - # will only send requests on connections that handle them. - # It's in place simply for resilience as a guard against incorrect - # usage, for anyone working directly with httpcore connections. - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - async with self._state_lock: - if self._state in (HTTPConnectionState.ACTIVE, HTTPConnectionState.IDLE): - self._request_count += 1 - self._expire_at = None - self._state = HTTPConnectionState.ACTIVE - else: - raise ConnectionNotAvailable() - - async with self._init_lock: - if not self._sent_connection_init: - try: - sci_kwargs = {"request": request} - async with Trace( - "send_connection_init", logger, request, sci_kwargs - ): - await self._send_connection_init(**sci_kwargs) - except BaseException as exc: - with AsyncShieldCancellation(): - await self.aclose() - raise exc - - self._sent_connection_init = True - - # Initially start with just 1 until the remote server provides - # its max_concurrent_streams value - self._max_streams = 1 - - local_settings_max_streams = ( - self._h2_state.local_settings.max_concurrent_streams - ) - self._max_streams_semaphore = AsyncSemaphore(local_settings_max_streams) - - for _ in range(local_settings_max_streams - self._max_streams): - await self._max_streams_semaphore.acquire() - - await self._max_streams_semaphore.acquire() - - try: - stream_id = self._h2_state.get_next_available_stream_id() - self._events[stream_id] = [] - except h2.exceptions.NoAvailableStreamIDError: # pragma: nocover - self._used_all_stream_ids = True - self._request_count -= 1 - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request, "stream_id": stream_id} - async with Trace("send_request_headers", logger, request, kwargs): - await self._send_request_headers(request=request, stream_id=stream_id) - async with Trace("send_request_body", logger, request, kwargs): - await self._send_request_body(request=request, stream_id=stream_id) - async with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - status, headers = await self._receive_response( - request=request, stream_id=stream_id - ) - trace.return_value = (status, headers) - - return Response( - status=status, - headers=headers, - content=HTTP2ConnectionByteStream(self, request, stream_id=stream_id), - extensions={ - "http_version": b"HTTP/2", - "network_stream": self._network_stream, - "stream_id": stream_id, - }, - ) - except BaseException as exc: # noqa: PIE786 - with AsyncShieldCancellation(): - kwargs = {"stream_id": stream_id} - async with Trace("response_closed", logger, request, kwargs): - await self._response_closed(stream_id=stream_id) - - if isinstance(exc, h2.exceptions.ProtocolError): - # One case where h2 can raise a protocol error is when a - # closed frame has been seen by the state machine. - # - # This happens when one stream is reading, and encounters - # a GOAWAY event. Other flows of control may then raise - # a protocol error at any point they interact with the 'h2_state'. - # - # In this case we'll have stored the event, and should raise - # it as a RemoteProtocolError. - if self._connection_terminated: # pragma: nocover - raise RemoteProtocolError(self._connection_terminated) - # If h2 raises a protocol error in some other state then we - # must somehow have made a protocol violation. - raise LocalProtocolError(exc) # pragma: nocover - - raise exc - - async def _send_connection_init(self, request: Request) -> None: - """ - The HTTP/2 connection requires some initial setup before we can start - using individual request/response streams on it. - """ - # Need to set these manually here instead of manipulating via - # __setitem__() otherwise the H2Connection will emit SettingsUpdate - # frames in addition to sending the undesired defaults. - self._h2_state.local_settings = h2.settings.Settings( - client=True, - initial_values={ - # Disable PUSH_PROMISE frames from the server since we don't do anything - # with them for now. Maybe when we support caching? - h2.settings.SettingCodes.ENABLE_PUSH: 0, - # These two are taken from h2 for safe defaults - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100, - h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 65536, - }, - ) - - # Some websites (*cough* Yahoo *cough*) balk at this setting being - # present in the initial handshake since it's not defined in the original - # RFC despite the RFC mandating ignoring settings you don't know about. - del self._h2_state.local_settings[ - h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL - ] - - self._h2_state.initiate_connection() - self._h2_state.increment_flow_control_window(2**24) - await self._write_outgoing_data(request) - - # Sending the request... - - async def _send_request_headers(self, request: Request, stream_id: int) -> None: - """ - Send the request headers to a given stream ID. - """ - end_stream = not has_body_headers(request) - - # In HTTP/2 the ':authority' pseudo-header is used instead of 'Host'. - # In order to gracefully handle HTTP/1.1 and HTTP/2 we always require - # HTTP/1.1 style headers, and map them appropriately if we end up on - # an HTTP/2 connection. - authority = [v for k, v in request.headers if k.lower() == b"host"][0] - - headers = [ - (b":method", request.method), - (b":authority", authority), - (b":scheme", request.url.scheme), - (b":path", request.url.target), - ] + [ - (k.lower(), v) - for k, v in request.headers - if k.lower() - not in ( - b"host", - b"transfer-encoding", - ) - ] - - self._h2_state.send_headers(stream_id, headers, end_stream=end_stream) - self._h2_state.increment_flow_control_window(2**24, stream_id=stream_id) - await self._write_outgoing_data(request) - - async def _send_request_body(self, request: Request, stream_id: int) -> None: - """ - Iterate over the request body sending it to a given stream ID. - """ - if not has_body_headers(request): - return - - assert isinstance(request.stream, typing.AsyncIterable) - async for data in request.stream: - await self._send_stream_data(request, stream_id, data) - await self._send_end_stream(request, stream_id) - - async def _send_stream_data( - self, request: Request, stream_id: int, data: bytes - ) -> None: - """ - Send a single chunk of data in one or more data frames. - """ - while data: - max_flow = await self._wait_for_outgoing_flow(request, stream_id) - chunk_size = min(len(data), max_flow) - chunk, data = data[:chunk_size], data[chunk_size:] - self._h2_state.send_data(stream_id, chunk) - await self._write_outgoing_data(request) - - async def _send_end_stream(self, request: Request, stream_id: int) -> None: - """ - Send an empty data frame on on a given stream ID with the END_STREAM flag set. - """ - self._h2_state.end_stream(stream_id) - await self._write_outgoing_data(request) - - # Receiving the response... - - async def _receive_response( - self, request: Request, stream_id: int - ) -> tuple[int, list[tuple[bytes, bytes]]]: - """ - Return the response status code and headers for a given stream ID. - """ - while True: - event = await self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.ResponseReceived): - break - - status_code = 200 - headers = [] - assert event.headers is not None - for k, v in event.headers: - if k == b":status": - status_code = int(v.decode("ascii", errors="ignore")) - elif not k.startswith(b":"): - headers.append((k, v)) - - return (status_code, headers) - - async def _receive_response_body( - self, request: Request, stream_id: int - ) -> typing.AsyncIterator[bytes]: - """ - Iterator that returns the bytes of the response body for a given stream ID. - """ - while True: - event = await self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.DataReceived): - assert event.flow_controlled_length is not None - assert event.data is not None - amount = event.flow_controlled_length - self._h2_state.acknowledge_received_data(amount, stream_id) - await self._write_outgoing_data(request) - yield event.data - elif isinstance(event, h2.events.StreamEnded): - break - - async def _receive_stream_event( - self, request: Request, stream_id: int - ) -> h2.events.ResponseReceived | h2.events.DataReceived | h2.events.StreamEnded: - """ - Return the next available event for a given stream ID. - - Will read more data from the network if required. - """ - while not self._events.get(stream_id): - await self._receive_events(request, stream_id) - event = self._events[stream_id].pop(0) - if isinstance(event, h2.events.StreamReset): - raise RemoteProtocolError(event) - return event - - async def _receive_events( - self, request: Request, stream_id: int | None = None - ) -> None: - """ - Read some data from the network until we see one or more events - for a given stream ID. - """ - async with self._read_lock: - if self._connection_terminated is not None: - last_stream_id = self._connection_terminated.last_stream_id - if stream_id and last_stream_id and stream_id > last_stream_id: - self._request_count -= 1 - raise ConnectionNotAvailable() - raise RemoteProtocolError(self._connection_terminated) - - # This conditional is a bit icky. We don't want to block reading if we've - # actually got an event to return for a given stream. We need to do that - # check *within* the atomic read lock. Though it also need to be optional, - # because when we call it from `_wait_for_outgoing_flow` we *do* want to - # block until we've available flow control, event when we have events - # pending for the stream ID we're attempting to send on. - if stream_id is None or not self._events.get(stream_id): - events = await self._read_incoming_data(request) - for event in events: - if isinstance(event, h2.events.RemoteSettingsChanged): - async with Trace( - "receive_remote_settings", logger, request - ) as trace: - await self._receive_remote_settings_change(event) - trace.return_value = event - - elif isinstance( - event, - ( - h2.events.ResponseReceived, - h2.events.DataReceived, - h2.events.StreamEnded, - h2.events.StreamReset, - ), - ): - if event.stream_id in self._events: - self._events[event.stream_id].append(event) - - elif isinstance(event, h2.events.ConnectionTerminated): - self._connection_terminated = event - - await self._write_outgoing_data(request) - - async def _receive_remote_settings_change( - self, event: h2.events.RemoteSettingsChanged - ) -> None: - max_concurrent_streams = event.changed_settings.get( - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS - ) - if max_concurrent_streams: - new_max_streams = min( - max_concurrent_streams.new_value, - self._h2_state.local_settings.max_concurrent_streams, - ) - if new_max_streams and new_max_streams != self._max_streams: - while new_max_streams > self._max_streams: - await self._max_streams_semaphore.release() - self._max_streams += 1 - while new_max_streams < self._max_streams: - await self._max_streams_semaphore.acquire() - self._max_streams -= 1 - - async def _response_closed(self, stream_id: int) -> None: - await self._max_streams_semaphore.release() - del self._events[stream_id] - async with self._state_lock: - if self._connection_terminated and not self._events: - await self.aclose() - - elif self._state == HTTPConnectionState.ACTIVE and not self._events: - self._state = HTTPConnectionState.IDLE - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - if self._used_all_stream_ids: # pragma: nocover - await self.aclose() - - async def aclose(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._h2_state.close_connection() - self._state = HTTPConnectionState.CLOSED - await self._network_stream.aclose() - - # Wrappers around network read/write operations... - - async def _read_incoming_data(self, request: Request) -> list[h2.events.Event]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - if self._read_exception is not None: - raise self._read_exception # pragma: nocover - - try: - data = await self._network_stream.read(self.READ_NUM_BYTES, timeout) - if data == b"": - raise RemoteProtocolError("Server disconnected") - except Exception as exc: - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future reads. - # (For example, this means that a single read timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._read_exception = exc - self._connection_error = True - raise exc - - events: list[h2.events.Event] = self._h2_state.receive_data(data) - - return events - - async def _write_outgoing_data(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - async with self._write_lock: - data_to_send = self._h2_state.data_to_send() - - if self._write_exception is not None: - raise self._write_exception # pragma: nocover - - try: - await self._network_stream.write(data_to_send, timeout) - except Exception as exc: # pragma: nocover - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future write. - # (For example, this means that a single write timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._write_exception = exc - self._connection_error = True - raise exc - - # Flow control... - - async def _wait_for_outgoing_flow(self, request: Request, stream_id: int) -> int: - """ - Returns the maximum allowable outgoing flow for a given stream. - - If the allowable flow is zero, then waits on the network until - WindowUpdated frames have increased the flow rate. - https://tools.ietf.org/html/rfc7540#section-6.9 - """ - local_flow: int = self._h2_state.local_flow_control_window(stream_id) - max_frame_size: int = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - while flow == 0: - await self._receive_events(request) - local_flow = self._h2_state.local_flow_control_window(stream_id) - max_frame_size = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - return flow - - # Interface for connection pooling... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - return ( - self._state != HTTPConnectionState.CLOSED - and not self._connection_error - and not self._used_all_stream_ids - and not ( - self._h2_state.state_machine.state - == h2.connection.ConnectionState.CLOSED - ) - ) - - def has_expired(self) -> bool: - now = time.monotonic() - return self._expire_at is not None and now > self._expire_at - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/2, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - async def __aenter__(self) -> AsyncHTTP2Connection: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() - - -class HTTP2ConnectionByteStream: - def __init__( - self, connection: AsyncHTTP2Connection, request: Request, stream_id: int - ) -> None: - self._connection = connection - self._request = request - self._stream_id = stream_id - self._closed = False - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - kwargs = {"request": self._request, "stream_id": self._stream_id} - try: - async with Trace("receive_response_body", logger, self._request, kwargs): - async for chunk in self._connection._receive_response_body( - request=self._request, stream_id=self._stream_id - ): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with AsyncShieldCancellation(): - await self.aclose() - raise exc - - async def aclose(self) -> None: - if not self._closed: - self._closed = True - kwargs = {"stream_id": self._stream_id} - async with Trace("response_closed", logger, self._request, kwargs): - await self._connection._response_closed(stream_id=self._stream_id) diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/http_proxy.py b/venv/lib/python3.10/site-packages/httpcore/_async/http_proxy.py deleted file mode 100644 index cc9d92066e1680576846e46ccdf645a2b1dd5718..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/http_proxy.py +++ /dev/null @@ -1,367 +0,0 @@ -from __future__ import annotations - -import base64 -import logging -import ssl -import typing - -from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend -from .._exceptions import ProxyError -from .._models import ( - URL, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, -) -from .._ssl import default_ssl_context -from .._synchronization import AsyncLock -from .._trace import Trace -from .connection import AsyncHTTPConnection -from .connection_pool import AsyncConnectionPool -from .http11 import AsyncHTTP11Connection -from .interfaces import AsyncConnectionInterface - -ByteOrStr = typing.Union[bytes, str] -HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] -HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] - - -logger = logging.getLogger("httpcore.proxy") - - -def merge_headers( - default_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - override_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, -) -> list[tuple[bytes, bytes]]: - """ - Append default_headers and override_headers, de-duplicating if a key exists - in both cases. - """ - default_headers = [] if default_headers is None else list(default_headers) - override_headers = [] if override_headers is None else list(override_headers) - has_override = set(key.lower() for key, value in override_headers) - default_headers = [ - (key, value) - for key, value in default_headers - if key.lower() not in has_override - ] - return default_headers + override_headers - - -class AsyncHTTPProxy(AsyncConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - proxy_auth: Any proxy authentication as a two-tuple of - (username, password). May be either bytes or ascii-only str. - proxy_headers: Any HTTP headers to use for the proxy requests. - For example `{"Proxy-Authorization": "Basic :"}`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - proxy_ssl_context: The same as `ssl_context`, but for a proxy server rather than a remote origin. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - local_address=local_address, - uds=uds, - socket_options=socket_options, - ) - - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if ( - self._proxy_url.scheme == b"http" and proxy_ssl_context is not None - ): # pragma: no cover - raise RuntimeError( - "The `proxy_ssl_context` argument is not allowed for the http scheme" - ) - - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - if proxy_auth is not None: - username = enforce_bytes(proxy_auth[0], name="proxy_auth") - password = enforce_bytes(proxy_auth[1], name="proxy_auth") - userpass = username + b":" + password - authorization = b"Basic " + base64.b64encode(userpass) - self._proxy_headers = [ - (b"Proxy-Authorization", authorization) - ] + self._proxy_headers - - def create_connection(self, origin: Origin) -> AsyncConnectionInterface: - if origin.scheme == b"http": - return AsyncForwardHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - proxy_ssl_context=self._proxy_ssl_context, - ) - return AsyncTunnelHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - ssl_context=self._ssl_context, - proxy_ssl_context=self._proxy_ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class AsyncForwardHTTPConnection(AsyncConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - keepalive_expiry: float | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - ) -> None: - self._connection = AsyncHTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._remote_origin = remote_origin - - async def handle_async_request(self, request: Request) -> Response: - headers = merge_headers(self._proxy_headers, request.headers) - url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=bytes(request.url), - ) - proxy_request = Request( - method=request.method, - url=url, - headers=headers, - content=request.stream, - extensions=request.extensions, - ) - return await self._connection.handle_async_request(proxy_request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - async def aclose(self) -> None: - await self._connection.aclose() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - -class AsyncTunnelHTTPConnection(AsyncConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - proxy_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._connection: AsyncConnectionInterface = AsyncHTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._connect_lock = AsyncLock() - self._connected = False - - async def handle_async_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("connect", None) - - async with self._connect_lock: - if not self._connected: - target = b"%b:%d" % (self._remote_origin.host, self._remote_origin.port) - - connect_url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=target, - ) - connect_headers = merge_headers( - [(b"Host", target), (b"Accept", b"*/*")], self._proxy_headers - ) - connect_request = Request( - method=b"CONNECT", - url=connect_url, - headers=connect_headers, - extensions=request.extensions, - ) - connect_response = await self._connection.handle_async_request( - connect_request - ) - - if connect_response.status < 200 or connect_response.status > 299: - reason_bytes = connect_response.extensions.get("reason_phrase", b"") - reason_str = reason_bytes.decode("ascii", errors="ignore") - msg = "%d %s" % (connect_response.status, reason_str) - await self._connection.aclose() - raise ProxyError(msg) - - stream = connect_response.extensions["network_stream"] - - # Upgrade the stream to SSL - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - async with Trace("start_tls", logger, request, kwargs) as trace: - stream = await stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import AsyncHTTP2Connection - - self._connection = AsyncHTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = AsyncHTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - - self._connected = True - return await self._connection.handle_async_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - async def aclose(self) -> None: - await self._connection.aclose() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/interfaces.py b/venv/lib/python3.10/site-packages/httpcore/_async/interfaces.py deleted file mode 100644 index 361583bede6b2b84088b38054d5d8116ef9f1597..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/interfaces.py +++ /dev/null @@ -1,137 +0,0 @@ -from __future__ import annotations - -import contextlib -import typing - -from .._models import ( - URL, - Extensions, - HeaderTypes, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, - include_request_headers, -) - - -class AsyncRequestInterface: - async def request( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.AsyncIterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> Response: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = await self.handle_async_request(request) - try: - await response.aread() - finally: - await response.aclose() - return response - - @contextlib.asynccontextmanager - async def stream( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.AsyncIterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> typing.AsyncIterator[Response]: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = await self.handle_async_request(request) - try: - yield response - finally: - await response.aclose() - - async def handle_async_request(self, request: Request) -> Response: - raise NotImplementedError() # pragma: nocover - - -class AsyncConnectionInterface(AsyncRequestInterface): - async def aclose(self) -> None: - raise NotImplementedError() # pragma: nocover - - def info(self) -> str: - raise NotImplementedError() # pragma: nocover - - def can_handle_request(self, origin: Origin) -> bool: - raise NotImplementedError() # pragma: nocover - - def is_available(self) -> bool: - """ - Return `True` if the connection is currently able to accept an - outgoing request. - - An HTTP/1.1 connection will only be available if it is currently idle. - - An HTTP/2 connection will be available so long as the stream ID space is - not yet exhausted, and the connection is not in an error state. - - While the connection is being established we may not yet know if it is going - to result in an HTTP/1.1 or HTTP/2 connection. The connection should be - treated as being available, but might ultimately raise `NewConnectionRequired` - required exceptions if multiple requests are attempted over a connection - that ends up being established as HTTP/1.1. - """ - raise NotImplementedError() # pragma: nocover - - def has_expired(self) -> bool: - """ - Return `True` if the connection is in a state where it should be closed. - - This either means that the connection is idle and it has passed the - expiry time on its keep-alive, or that server has sent an EOF. - """ - raise NotImplementedError() # pragma: nocover - - def is_idle(self) -> bool: - """ - Return `True` if the connection is currently idle. - """ - raise NotImplementedError() # pragma: nocover - - def is_closed(self) -> bool: - """ - Return `True` if the connection has been closed. - - Used when a response is closed to determine if the connection may be - returned to the connection pool or not. - """ - raise NotImplementedError() # pragma: nocover diff --git a/venv/lib/python3.10/site-packages/httpcore/_async/socks_proxy.py b/venv/lib/python3.10/site-packages/httpcore/_async/socks_proxy.py deleted file mode 100644 index b363f55a0b071de6c5f377726be82dc2110e373c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_async/socks_proxy.py +++ /dev/null @@ -1,341 +0,0 @@ -from __future__ import annotations - -import logging -import ssl - -import socksio - -from .._backends.auto import AutoBackend -from .._backends.base import AsyncNetworkBackend, AsyncNetworkStream -from .._exceptions import ConnectionNotAvailable, ProxyError -from .._models import URL, Origin, Request, Response, enforce_bytes, enforce_url -from .._ssl import default_ssl_context -from .._synchronization import AsyncLock -from .._trace import Trace -from .connection_pool import AsyncConnectionPool -from .http11 import AsyncHTTP11Connection -from .interfaces import AsyncConnectionInterface - -logger = logging.getLogger("httpcore.socks") - - -AUTH_METHODS = { - b"\x00": "NO AUTHENTICATION REQUIRED", - b"\x01": "GSSAPI", - b"\x02": "USERNAME/PASSWORD", - b"\xff": "NO ACCEPTABLE METHODS", -} - -REPLY_CODES = { - b"\x00": "Succeeded", - b"\x01": "General SOCKS server failure", - b"\x02": "Connection not allowed by ruleset", - b"\x03": "Network unreachable", - b"\x04": "Host unreachable", - b"\x05": "Connection refused", - b"\x06": "TTL expired", - b"\x07": "Command not supported", - b"\x08": "Address type not supported", -} - - -async def _init_socks5_connection( - stream: AsyncNetworkStream, - *, - host: bytes, - port: int, - auth: tuple[bytes, bytes] | None = None, -) -> None: - conn = socksio.socks5.SOCKS5Connection() - - # Auth method request - auth_method = ( - socksio.socks5.SOCKS5AuthMethod.NO_AUTH_REQUIRED - if auth is None - else socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD - ) - conn.send(socksio.socks5.SOCKS5AuthMethodsRequest([auth_method])) - outgoing_bytes = conn.data_to_send() - await stream.write(outgoing_bytes) - - # Auth method response - incoming_bytes = await stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5AuthReply) - if response.method != auth_method: - requested = AUTH_METHODS.get(auth_method, "UNKNOWN") - responded = AUTH_METHODS.get(response.method, "UNKNOWN") - raise ProxyError( - f"Requested {requested} from proxy server, but got {responded}." - ) - - if response.method == socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD: - # Username/password request - assert auth is not None - username, password = auth - conn.send(socksio.socks5.SOCKS5UsernamePasswordRequest(username, password)) - outgoing_bytes = conn.data_to_send() - await stream.write(outgoing_bytes) - - # Username/password response - incoming_bytes = await stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5UsernamePasswordReply) - if not response.success: - raise ProxyError("Invalid username/password") - - # Connect request - conn.send( - socksio.socks5.SOCKS5CommandRequest.from_address( - socksio.socks5.SOCKS5Command.CONNECT, (host, port) - ) - ) - outgoing_bytes = conn.data_to_send() - await stream.write(outgoing_bytes) - - # Connect response - incoming_bytes = await stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5Reply) - if response.reply_code != socksio.socks5.SOCKS5ReplyCode.SUCCEEDED: - reply_code = REPLY_CODES.get(response.reply_code, "UNKOWN") - raise ProxyError(f"Proxy Server could not connect: {reply_code}.") - - -class AsyncSOCKSProxy(AsyncConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - network_backend: AsyncNetworkBackend | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - ) - self._ssl_context = ssl_context - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if proxy_auth is not None: - username, password = proxy_auth - username_bytes = enforce_bytes(username, name="proxy_auth") - password_bytes = enforce_bytes(password, name="proxy_auth") - self._proxy_auth: tuple[bytes, bytes] | None = ( - username_bytes, - password_bytes, - ) - else: - self._proxy_auth = None - - def create_connection(self, origin: Origin) -> AsyncConnectionInterface: - return AsyncSocks5Connection( - proxy_origin=self._proxy_url.origin, - remote_origin=origin, - proxy_auth=self._proxy_auth, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class AsyncSocks5Connection(AsyncConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_auth: tuple[bytes, bytes] | None = None, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: AsyncNetworkBackend | None = None, - ) -> None: - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._proxy_auth = proxy_auth - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - - self._network_backend: AsyncNetworkBackend = ( - AutoBackend() if network_backend is None else network_backend - ) - self._connect_lock = AsyncLock() - self._connection: AsyncConnectionInterface | None = None - self._connect_failed = False - - async def handle_async_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - async with self._connect_lock: - if self._connection is None: - try: - # Connect to the proxy - kwargs = { - "host": self._proxy_origin.host.decode("ascii"), - "port": self._proxy_origin.port, - "timeout": timeout, - } - async with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = await self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - - # Connect to the remote host using socks5 - kwargs = { - "stream": stream, - "host": self._remote_origin.host.decode("ascii"), - "port": self._remote_origin.port, - "auth": self._proxy_auth, - } - async with Trace( - "setup_socks5_connection", logger, request, kwargs - ) as trace: - await _init_socks5_connection(**kwargs) - trace.return_value = stream - - # Upgrade the stream to SSL - if self._remote_origin.scheme == b"https": - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ( - ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ) - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - async with Trace("start_tls", logger, request, kwargs) as trace: - stream = await stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or ( - self._http2 and not self._http1 - ): # pragma: nocover - from .http2 import AsyncHTTP2Connection - - self._connection = AsyncHTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = AsyncHTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except Exception as exc: - self._connect_failed = True - raise exc - elif not self._connection.is_available(): # pragma: nocover - raise ConnectionNotAvailable() - - return await self._connection.handle_async_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - async def aclose(self) -> None: - if self._connection is not None: - await self._connection.aclose() - - def is_available(self) -> bool: - if self._connection is None: # pragma: nocover - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._remote_origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: # pragma: nocover - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__init__.py b/venv/lib/python3.10/site-packages/httpcore/_backends/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index ff0f42573f89424c9d4d39eaa53765855a8aa475..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/anyio.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/anyio.cpython-310.pyc deleted file mode 100644 index 53aec97ee5378c804f4f2bce11eba73099b7c9f5..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/anyio.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/auto.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/auto.cpython-310.pyc deleted file mode 100644 index 670563658cf6d71fb43cd830c73586c69a83e6b4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/auto.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/base.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/base.cpython-310.pyc deleted file mode 100644 index 7b4aae61338758ae0f132a76b86e30e3500fa20d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/base.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/mock.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/mock.cpython-310.pyc deleted file mode 100644 index 6cd179f0e6c1fecd9ab56c6757e71b95238a372f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/mock.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/sync.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/sync.cpython-310.pyc deleted file mode 100644 index 1524cd777cc7e8576bb91880c2b54cd53542ffb4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/sync.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/trio.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/trio.cpython-310.pyc deleted file mode 100644 index d19067460c46ecaa360f4169d32e30b836ee24eb..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_backends/__pycache__/trio.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/anyio.py b/venv/lib/python3.10/site-packages/httpcore/_backends/anyio.py deleted file mode 100644 index a140095e1b8de022f321a41c0125e0e5febc0749..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_backends/anyio.py +++ /dev/null @@ -1,146 +0,0 @@ -from __future__ import annotations - -import ssl -import typing - -import anyio - -from .._exceptions import ( - ConnectError, - ConnectTimeout, - ReadError, - ReadTimeout, - WriteError, - WriteTimeout, - map_exceptions, -) -from .._utils import is_socket_readable -from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream - - -class AnyIOStream(AsyncNetworkStream): - def __init__(self, stream: anyio.abc.ByteStream) -> None: - self._stream = stream - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - exc_map = { - TimeoutError: ReadTimeout, - anyio.BrokenResourceError: ReadError, - anyio.ClosedResourceError: ReadError, - anyio.EndOfStream: ReadError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - try: - return await self._stream.receive(max_bytes=max_bytes) - except anyio.EndOfStream: # pragma: nocover - return b"" - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - if not buffer: - return - - exc_map = { - TimeoutError: WriteTimeout, - anyio.BrokenResourceError: WriteError, - anyio.ClosedResourceError: WriteError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - await self._stream.send(item=buffer) - - async def aclose(self) -> None: - await self._stream.aclose() - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - exc_map = { - TimeoutError: ConnectTimeout, - anyio.BrokenResourceError: ConnectError, - anyio.EndOfStream: ConnectError, - ssl.SSLError: ConnectError, - } - with map_exceptions(exc_map): - try: - with anyio.fail_after(timeout): - ssl_stream = await anyio.streams.tls.TLSStream.wrap( - self._stream, - ssl_context=ssl_context, - hostname=server_hostname, - standard_compatible=False, - server_side=False, - ) - except Exception as exc: # pragma: nocover - await self.aclose() - raise exc - return AnyIOStream(ssl_stream) - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object": - return self._stream.extra(anyio.streams.tls.TLSAttribute.ssl_object, None) - if info == "client_addr": - return self._stream.extra(anyio.abc.SocketAttribute.local_address, None) - if info == "server_addr": - return self._stream.extra(anyio.abc.SocketAttribute.remote_address, None) - if info == "socket": - return self._stream.extra(anyio.abc.SocketAttribute.raw_socket, None) - if info == "is_readable": - sock = self._stream.extra(anyio.abc.SocketAttribute.raw_socket, None) - return is_socket_readable(sock) - return None - - -class AnyIOBackend(AsyncNetworkBackend): - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - if socket_options is None: - socket_options = [] - exc_map = { - TimeoutError: ConnectTimeout, - OSError: ConnectError, - anyio.BrokenResourceError: ConnectError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - stream: anyio.abc.ByteStream = await anyio.connect_tcp( - remote_host=host, - remote_port=port, - local_host=local_address, - ) - # By default TCP sockets opened in `asyncio` include TCP_NODELAY. - for option in socket_options: - stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return AnyIOStream(stream) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - if socket_options is None: - socket_options = [] - exc_map = { - TimeoutError: ConnectTimeout, - OSError: ConnectError, - anyio.BrokenResourceError: ConnectError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - stream: anyio.abc.ByteStream = await anyio.connect_unix(path) - for option in socket_options: - stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return AnyIOStream(stream) - - async def sleep(self, seconds: float) -> None: - await anyio.sleep(seconds) # pragma: nocover diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/auto.py b/venv/lib/python3.10/site-packages/httpcore/_backends/auto.py deleted file mode 100644 index 49f0e698c97ad5623f376d8182675352e21c2c3c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_backends/auto.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import annotations - -import typing - -from .._synchronization import current_async_library -from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream - - -class AutoBackend(AsyncNetworkBackend): - async def _init_backend(self) -> None: - if not (hasattr(self, "_backend")): - backend = current_async_library() - if backend == "trio": - from .trio import TrioBackend - - self._backend: AsyncNetworkBackend = TrioBackend() - else: - from .anyio import AnyIOBackend - - self._backend = AnyIOBackend() - - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - await self._init_backend() - return await self._backend.connect_tcp( - host, - port, - timeout=timeout, - local_address=local_address, - socket_options=socket_options, - ) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - await self._init_backend() - return await self._backend.connect_unix_socket( - path, timeout=timeout, socket_options=socket_options - ) - - async def sleep(self, seconds: float) -> None: # pragma: nocover - await self._init_backend() - return await self._backend.sleep(seconds) diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/base.py b/venv/lib/python3.10/site-packages/httpcore/_backends/base.py deleted file mode 100644 index cf55c8b10eb543872550be863206fe2f760d0d8d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_backends/base.py +++ /dev/null @@ -1,101 +0,0 @@ -from __future__ import annotations - -import ssl -import time -import typing - -SOCKET_OPTION = typing.Union[ - typing.Tuple[int, int, int], - typing.Tuple[int, int, typing.Union[bytes, bytearray]], - typing.Tuple[int, int, None, int], -] - - -class NetworkStream: - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - raise NotImplementedError() # pragma: nocover - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - raise NotImplementedError() # pragma: nocover - - def close(self) -> None: - raise NotImplementedError() # pragma: nocover - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - raise NotImplementedError() # pragma: nocover - - def get_extra_info(self, info: str) -> typing.Any: - return None # pragma: nocover - - -class NetworkBackend: - def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - raise NotImplementedError() # pragma: nocover - - def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - raise NotImplementedError() # pragma: nocover - - def sleep(self, seconds: float) -> None: - time.sleep(seconds) # pragma: nocover - - -class AsyncNetworkStream: - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - raise NotImplementedError() # pragma: nocover - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - raise NotImplementedError() # pragma: nocover - - async def aclose(self) -> None: - raise NotImplementedError() # pragma: nocover - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - raise NotImplementedError() # pragma: nocover - - def get_extra_info(self, info: str) -> typing.Any: - return None # pragma: nocover - - -class AsyncNetworkBackend: - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - raise NotImplementedError() # pragma: nocover - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - raise NotImplementedError() # pragma: nocover - - async def sleep(self, seconds: float) -> None: - raise NotImplementedError() # pragma: nocover diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/mock.py b/venv/lib/python3.10/site-packages/httpcore/_backends/mock.py deleted file mode 100644 index 9b6edca03d4d4b34f355fd53e49d4b4c699c972c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_backends/mock.py +++ /dev/null @@ -1,143 +0,0 @@ -from __future__ import annotations - -import ssl -import typing - -from .._exceptions import ReadError -from .base import ( - SOCKET_OPTION, - AsyncNetworkBackend, - AsyncNetworkStream, - NetworkBackend, - NetworkStream, -) - - -class MockSSLObject: - def __init__(self, http2: bool): - self._http2 = http2 - - def selected_alpn_protocol(self) -> str: - return "h2" if self._http2 else "http/1.1" - - -class MockStream(NetworkStream): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - self._closed = False - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._closed: - raise ReadError("Connection closed") - if not self._buffer: - return b"" - return self._buffer.pop(0) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - pass - - def close(self) -> None: - self._closed = True - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - return self - - def get_extra_info(self, info: str) -> typing.Any: - return MockSSLObject(http2=self._http2) if info == "ssl_object" else None - - def __repr__(self) -> str: - return "" - - -class MockBackend(NetworkBackend): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - - def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - return MockStream(list(self._buffer), http2=self._http2) - - def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - return MockStream(list(self._buffer), http2=self._http2) - - def sleep(self, seconds: float) -> None: - pass - - -class AsyncMockStream(AsyncNetworkStream): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - self._closed = False - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._closed: - raise ReadError("Connection closed") - if not self._buffer: - return b"" - return self._buffer.pop(0) - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - pass - - async def aclose(self) -> None: - self._closed = True - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - return self - - def get_extra_info(self, info: str) -> typing.Any: - return MockSSLObject(http2=self._http2) if info == "ssl_object" else None - - def __repr__(self) -> str: - return "" - - -class AsyncMockBackend(AsyncNetworkBackend): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - return AsyncMockStream(list(self._buffer), http2=self._http2) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - return AsyncMockStream(list(self._buffer), http2=self._http2) - - async def sleep(self, seconds: float) -> None: - pass diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/sync.py b/venv/lib/python3.10/site-packages/httpcore/_backends/sync.py deleted file mode 100644 index 4018a09c6fb1e0ef1b03ab8d84b13ebef4031f7c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_backends/sync.py +++ /dev/null @@ -1,241 +0,0 @@ -from __future__ import annotations - -import functools -import socket -import ssl -import sys -import typing - -from .._exceptions import ( - ConnectError, - ConnectTimeout, - ExceptionMapping, - ReadError, - ReadTimeout, - WriteError, - WriteTimeout, - map_exceptions, -) -from .._utils import is_socket_readable -from .base import SOCKET_OPTION, NetworkBackend, NetworkStream - - -class TLSinTLSStream(NetworkStream): # pragma: no cover - """ - Because the standard `SSLContext.wrap_socket` method does - not work for `SSLSocket` objects, we need this class - to implement TLS stream using an underlying `SSLObject` - instance in order to support TLS on top of TLS. - """ - - # Defined in RFC 8449 - TLS_RECORD_SIZE = 16384 - - def __init__( - self, - sock: socket.socket, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ): - self._sock = sock - self._incoming = ssl.MemoryBIO() - self._outgoing = ssl.MemoryBIO() - - self.ssl_obj = ssl_context.wrap_bio( - incoming=self._incoming, - outgoing=self._outgoing, - server_hostname=server_hostname, - ) - - self._sock.settimeout(timeout) - self._perform_io(self.ssl_obj.do_handshake) - - def _perform_io( - self, - func: typing.Callable[..., typing.Any], - ) -> typing.Any: - ret = None - - while True: - errno = None - try: - ret = func() - except (ssl.SSLWantReadError, ssl.SSLWantWriteError) as e: - errno = e.errno - - self._sock.sendall(self._outgoing.read()) - - if errno == ssl.SSL_ERROR_WANT_READ: - buf = self._sock.recv(self.TLS_RECORD_SIZE) - - if buf: - self._incoming.write(buf) - else: - self._incoming.write_eof() - if errno is None: - return ret - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError} - with map_exceptions(exc_map): - self._sock.settimeout(timeout) - return typing.cast( - bytes, self._perform_io(functools.partial(self.ssl_obj.read, max_bytes)) - ) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError} - with map_exceptions(exc_map): - self._sock.settimeout(timeout) - while buffer: - nsent = self._perform_io(functools.partial(self.ssl_obj.write, buffer)) - buffer = buffer[nsent:] - - def close(self) -> None: - self._sock.close() - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - raise NotImplementedError() - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object": - return self.ssl_obj - if info == "client_addr": - return self._sock.getsockname() - if info == "server_addr": - return self._sock.getpeername() - if info == "socket": - return self._sock - if info == "is_readable": - return is_socket_readable(self._sock) - return None - - -class SyncStream(NetworkStream): - def __init__(self, sock: socket.socket) -> None: - self._sock = sock - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError} - with map_exceptions(exc_map): - self._sock.settimeout(timeout) - return self._sock.recv(max_bytes) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - if not buffer: - return - - exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError} - with map_exceptions(exc_map): - while buffer: - self._sock.settimeout(timeout) - n = self._sock.send(buffer) - buffer = buffer[n:] - - def close(self) -> None: - self._sock.close() - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - exc_map: ExceptionMapping = { - socket.timeout: ConnectTimeout, - OSError: ConnectError, - } - with map_exceptions(exc_map): - try: - if isinstance(self._sock, ssl.SSLSocket): # pragma: no cover - # If the underlying socket has already been upgraded - # to the TLS layer (i.e. is an instance of SSLSocket), - # we need some additional smarts to support TLS-in-TLS. - return TLSinTLSStream( - self._sock, ssl_context, server_hostname, timeout - ) - else: - self._sock.settimeout(timeout) - sock = ssl_context.wrap_socket( - self._sock, server_hostname=server_hostname - ) - except Exception as exc: # pragma: nocover - self.close() - raise exc - return SyncStream(sock) - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object" and isinstance(self._sock, ssl.SSLSocket): - return self._sock._sslobj # type: ignore - if info == "client_addr": - return self._sock.getsockname() - if info == "server_addr": - return self._sock.getpeername() - if info == "socket": - return self._sock - if info == "is_readable": - return is_socket_readable(self._sock) - return None - - -class SyncBackend(NetworkBackend): - def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - # Note that we automatically include `TCP_NODELAY` - # in addition to any other custom socket options. - if socket_options is None: - socket_options = [] # pragma: no cover - address = (host, port) - source_address = None if local_address is None else (local_address, 0) - exc_map: ExceptionMapping = { - socket.timeout: ConnectTimeout, - OSError: ConnectError, - } - - with map_exceptions(exc_map): - sock = socket.create_connection( - address, - timeout, - source_address=source_address, - ) - for option in socket_options: - sock.setsockopt(*option) # pragma: no cover - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - return SyncStream(sock) - - def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: # pragma: nocover - if sys.platform == "win32": - raise RuntimeError( - "Attempted to connect to a UNIX socket on a Windows system." - ) - if socket_options is None: - socket_options = [] - - exc_map: ExceptionMapping = { - socket.timeout: ConnectTimeout, - OSError: ConnectError, - } - with map_exceptions(exc_map): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - for option in socket_options: - sock.setsockopt(*option) - sock.settimeout(timeout) - sock.connect(path) - return SyncStream(sock) diff --git a/venv/lib/python3.10/site-packages/httpcore/_backends/trio.py b/venv/lib/python3.10/site-packages/httpcore/_backends/trio.py deleted file mode 100644 index 6f53f5f2a025e01e9949e2530bd9ca6928859251..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_backends/trio.py +++ /dev/null @@ -1,159 +0,0 @@ -from __future__ import annotations - -import ssl -import typing - -import trio - -from .._exceptions import ( - ConnectError, - ConnectTimeout, - ExceptionMapping, - ReadError, - ReadTimeout, - WriteError, - WriteTimeout, - map_exceptions, -) -from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream - - -class TrioStream(AsyncNetworkStream): - def __init__(self, stream: trio.abc.Stream) -> None: - self._stream = stream - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ReadTimeout, - trio.BrokenResourceError: ReadError, - trio.ClosedResourceError: ReadError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - data: bytes = await self._stream.receive_some(max_bytes=max_bytes) - return data - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - if not buffer: - return - - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: WriteTimeout, - trio.BrokenResourceError: WriteError, - trio.ClosedResourceError: WriteError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - await self._stream.send_all(data=buffer) - - async def aclose(self) -> None: - await self._stream.aclose() - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ConnectTimeout, - trio.BrokenResourceError: ConnectError, - } - ssl_stream = trio.SSLStream( - self._stream, - ssl_context=ssl_context, - server_hostname=server_hostname, - https_compatible=True, - server_side=False, - ) - with map_exceptions(exc_map): - try: - with trio.fail_after(timeout_or_inf): - await ssl_stream.do_handshake() - except Exception as exc: # pragma: nocover - await self.aclose() - raise exc - return TrioStream(ssl_stream) - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object" and isinstance(self._stream, trio.SSLStream): - # Type checkers cannot see `_ssl_object` attribute because trio._ssl.SSLStream uses __getattr__/__setattr__. - # Tracked at https://github.com/python-trio/trio/issues/542 - return self._stream._ssl_object # type: ignore[attr-defined] - if info == "client_addr": - return self._get_socket_stream().socket.getsockname() - if info == "server_addr": - return self._get_socket_stream().socket.getpeername() - if info == "socket": - stream = self._stream - while isinstance(stream, trio.SSLStream): - stream = stream.transport_stream - assert isinstance(stream, trio.SocketStream) - return stream.socket - if info == "is_readable": - socket = self.get_extra_info("socket") - return socket.is_readable() - return None - - def _get_socket_stream(self) -> trio.SocketStream: - stream = self._stream - while isinstance(stream, trio.SSLStream): - stream = stream.transport_stream - assert isinstance(stream, trio.SocketStream) - return stream - - -class TrioBackend(AsyncNetworkBackend): - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - # By default for TCP sockets, trio enables TCP_NODELAY. - # https://trio.readthedocs.io/en/stable/reference-io.html#trio.SocketStream - if socket_options is None: - socket_options = [] # pragma: no cover - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ConnectTimeout, - trio.BrokenResourceError: ConnectError, - OSError: ConnectError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - stream: trio.abc.Stream = await trio.open_tcp_stream( - host=host, port=port, local_address=local_address - ) - for option in socket_options: - stream.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return TrioStream(stream) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - if socket_options is None: - socket_options = [] - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ConnectTimeout, - trio.BrokenResourceError: ConnectError, - OSError: ConnectError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - stream: trio.abc.Stream = await trio.open_unix_socket(path) - for option in socket_options: - stream.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return TrioStream(stream) - - async def sleep(self, seconds: float) -> None: - await trio.sleep(seconds) # pragma: nocover diff --git a/venv/lib/python3.10/site-packages/httpcore/_exceptions.py b/venv/lib/python3.10/site-packages/httpcore/_exceptions.py deleted file mode 100644 index bc28d44f55bdc4b872951a74780469a3999d9ab4..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_exceptions.py +++ /dev/null @@ -1,81 +0,0 @@ -import contextlib -import typing - -ExceptionMapping = typing.Mapping[typing.Type[Exception], typing.Type[Exception]] - - -@contextlib.contextmanager -def map_exceptions(map: ExceptionMapping) -> typing.Iterator[None]: - try: - yield - except Exception as exc: # noqa: PIE786 - for from_exc, to_exc in map.items(): - if isinstance(exc, from_exc): - raise to_exc(exc) from exc - raise # pragma: nocover - - -class ConnectionNotAvailable(Exception): - pass - - -class ProxyError(Exception): - pass - - -class UnsupportedProtocol(Exception): - pass - - -class ProtocolError(Exception): - pass - - -class RemoteProtocolError(ProtocolError): - pass - - -class LocalProtocolError(ProtocolError): - pass - - -# Timeout errors - - -class TimeoutException(Exception): - pass - - -class PoolTimeout(TimeoutException): - pass - - -class ConnectTimeout(TimeoutException): - pass - - -class ReadTimeout(TimeoutException): - pass - - -class WriteTimeout(TimeoutException): - pass - - -# Network errors - - -class NetworkError(Exception): - pass - - -class ConnectError(NetworkError): - pass - - -class ReadError(NetworkError): - pass - - -class WriteError(NetworkError): - pass diff --git a/venv/lib/python3.10/site-packages/httpcore/_models.py b/venv/lib/python3.10/site-packages/httpcore/_models.py deleted file mode 100644 index 8a65f13347d6621289a166d08123cbc8e1ad0157..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_models.py +++ /dev/null @@ -1,516 +0,0 @@ -from __future__ import annotations - -import base64 -import ssl -import typing -import urllib.parse - -# Functions for typechecking... - - -ByteOrStr = typing.Union[bytes, str] -HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] -HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] -HeaderTypes = typing.Union[HeadersAsSequence, HeadersAsMapping, None] - -Extensions = typing.MutableMapping[str, typing.Any] - - -def enforce_bytes(value: bytes | str, *, name: str) -> bytes: - """ - Any arguments that are ultimately represented as bytes can be specified - either as bytes or as strings. - - However we enforce that any string arguments must only contain characters in - the plain ASCII range. chr(0)...chr(127). If you need to use characters - outside that range then be precise, and use a byte-wise argument. - """ - if isinstance(value, str): - try: - return value.encode("ascii") - except UnicodeEncodeError: - raise TypeError(f"{name} strings may not include unicode characters.") - elif isinstance(value, bytes): - return value - - seen_type = type(value).__name__ - raise TypeError(f"{name} must be bytes or str, but got {seen_type}.") - - -def enforce_url(value: URL | bytes | str, *, name: str) -> URL: - """ - Type check for URL parameters. - """ - if isinstance(value, (bytes, str)): - return URL(value) - elif isinstance(value, URL): - return value - - seen_type = type(value).__name__ - raise TypeError(f"{name} must be a URL, bytes, or str, but got {seen_type}.") - - -def enforce_headers( - value: HeadersAsMapping | HeadersAsSequence | None = None, *, name: str -) -> list[tuple[bytes, bytes]]: - """ - Convienence function that ensure all items in request or response headers - are either bytes or strings in the plain ASCII range. - """ - if value is None: - return [] - elif isinstance(value, typing.Mapping): - return [ - ( - enforce_bytes(k, name="header name"), - enforce_bytes(v, name="header value"), - ) - for k, v in value.items() - ] - elif isinstance(value, typing.Sequence): - return [ - ( - enforce_bytes(k, name="header name"), - enforce_bytes(v, name="header value"), - ) - for k, v in value - ] - - seen_type = type(value).__name__ - raise TypeError( - f"{name} must be a mapping or sequence of two-tuples, but got {seen_type}." - ) - - -def enforce_stream( - value: bytes | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None, - *, - name: str, -) -> typing.Iterable[bytes] | typing.AsyncIterable[bytes]: - if value is None: - return ByteStream(b"") - elif isinstance(value, bytes): - return ByteStream(value) - return value - - -# * https://tools.ietf.org/html/rfc3986#section-3.2.3 -# * https://url.spec.whatwg.org/#url-miscellaneous -# * https://url.spec.whatwg.org/#scheme-state -DEFAULT_PORTS = { - b"ftp": 21, - b"http": 80, - b"https": 443, - b"ws": 80, - b"wss": 443, -} - - -def include_request_headers( - headers: list[tuple[bytes, bytes]], - *, - url: "URL", - content: None | bytes | typing.Iterable[bytes] | typing.AsyncIterable[bytes], -) -> list[tuple[bytes, bytes]]: - headers_set = set(k.lower() for k, v in headers) - - if b"host" not in headers_set: - default_port = DEFAULT_PORTS.get(url.scheme) - if url.port is None or url.port == default_port: - header_value = url.host - else: - header_value = b"%b:%d" % (url.host, url.port) - headers = [(b"Host", header_value)] + headers - - if ( - content is not None - and b"content-length" not in headers_set - and b"transfer-encoding" not in headers_set - ): - if isinstance(content, bytes): - content_length = str(len(content)).encode("ascii") - headers += [(b"Content-Length", content_length)] - else: - headers += [(b"Transfer-Encoding", b"chunked")] # pragma: nocover - - return headers - - -# Interfaces for byte streams... - - -class ByteStream: - """ - A container for non-streaming content, and that supports both sync and async - stream iteration. - """ - - def __init__(self, content: bytes) -> None: - self._content = content - - def __iter__(self) -> typing.Iterator[bytes]: - yield self._content - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - yield self._content - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{len(self._content)} bytes]>" - - -class Origin: - def __init__(self, scheme: bytes, host: bytes, port: int) -> None: - self.scheme = scheme - self.host = host - self.port = port - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, Origin) - and self.scheme == other.scheme - and self.host == other.host - and self.port == other.port - ) - - def __str__(self) -> str: - scheme = self.scheme.decode("ascii") - host = self.host.decode("ascii") - port = str(self.port) - return f"{scheme}://{host}:{port}" - - -class URL: - """ - Represents the URL against which an HTTP request may be made. - - The URL may either be specified as a plain string, for convienence: - - ```python - url = httpcore.URL("https://www.example.com/") - ``` - - Or be constructed with explicitily pre-parsed components: - - ```python - url = httpcore.URL(scheme=b'https', host=b'www.example.com', port=None, target=b'/') - ``` - - Using this second more explicit style allows integrations that are using - `httpcore` to pass through URLs that have already been parsed in order to use - libraries such as `rfc-3986` rather than relying on the stdlib. It also ensures - that URL parsing is treated identically at both the networking level and at any - higher layers of abstraction. - - The four components are important here, as they allow the URL to be precisely - specified in a pre-parsed format. They also allow certain types of request to - be created that could not otherwise be expressed. - - For example, an HTTP request to `http://www.example.com/` forwarded via a proxy - at `http://localhost:8080`... - - ```python - # Constructs an HTTP request with a complete URL as the target: - # GET https://www.example.com/ HTTP/1.1 - url = httpcore.URL( - scheme=b'http', - host=b'localhost', - port=8080, - target=b'https://www.example.com/' - ) - request = httpcore.Request( - method="GET", - url=url - ) - ``` - - Another example is constructing an `OPTIONS *` request... - - ```python - # Constructs an 'OPTIONS *' HTTP request: - # OPTIONS * HTTP/1.1 - url = httpcore.URL(scheme=b'https', host=b'www.example.com', target=b'*') - request = httpcore.Request(method="OPTIONS", url=url) - ``` - - This kind of request is not possible to formulate with a URL string, - because the `/` delimiter is always used to demark the target from the - host/port portion of the URL. - - For convenience, string-like arguments may be specified either as strings or - as bytes. However, once a request is being issue over-the-wire, the URL - components are always ultimately required to be a bytewise representation. - - In order to avoid any ambiguity over character encodings, when strings are used - as arguments, they must be strictly limited to the ASCII range `chr(0)`-`chr(127)`. - If you require a bytewise representation that is outside this range you must - handle the character encoding directly, and pass a bytes instance. - """ - - def __init__( - self, - url: bytes | str = "", - *, - scheme: bytes | str = b"", - host: bytes | str = b"", - port: int | None = None, - target: bytes | str = b"", - ) -> None: - """ - Parameters: - url: The complete URL as a string or bytes. - scheme: The URL scheme as a string or bytes. - Typically either `"http"` or `"https"`. - host: The URL host as a string or bytes. Such as `"www.example.com"`. - port: The port to connect to. Either an integer or `None`. - target: The target of the HTTP request. Such as `"/items?search=red"`. - """ - if url: - parsed = urllib.parse.urlparse(enforce_bytes(url, name="url")) - self.scheme = parsed.scheme - self.host = parsed.hostname or b"" - self.port = parsed.port - self.target = (parsed.path or b"/") + ( - b"?" + parsed.query if parsed.query else b"" - ) - else: - self.scheme = enforce_bytes(scheme, name="scheme") - self.host = enforce_bytes(host, name="host") - self.port = port - self.target = enforce_bytes(target, name="target") - - @property - def origin(self) -> Origin: - default_port = { - b"http": 80, - b"https": 443, - b"ws": 80, - b"wss": 443, - b"socks5": 1080, - b"socks5h": 1080, - }[self.scheme] - return Origin( - scheme=self.scheme, host=self.host, port=self.port or default_port - ) - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, URL) - and other.scheme == self.scheme - and other.host == self.host - and other.port == self.port - and other.target == self.target - ) - - def __bytes__(self) -> bytes: - if self.port is None: - return b"%b://%b%b" % (self.scheme, self.host, self.target) - return b"%b://%b:%d%b" % (self.scheme, self.host, self.port, self.target) - - def __repr__(self) -> str: - return ( - f"{self.__class__.__name__}(scheme={self.scheme!r}, " - f"host={self.host!r}, port={self.port!r}, target={self.target!r})" - ) - - -class Request: - """ - An HTTP request. - """ - - def __init__( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes - | typing.Iterable[bytes] - | typing.AsyncIterable[bytes] - | None = None, - extensions: Extensions | None = None, - ) -> None: - """ - Parameters: - method: The HTTP request method, either as a string or bytes. - For example: `GET`. - url: The request URL, either as a `URL` instance, or as a string or bytes. - For example: `"https://www.example.com".` - headers: The HTTP request headers. - content: The content of the request body. - extensions: A dictionary of optional extra information included on - the request. Possible keys include `"timeout"`, and `"trace"`. - """ - self.method: bytes = enforce_bytes(method, name="method") - self.url: URL = enforce_url(url, name="url") - self.headers: list[tuple[bytes, bytes]] = enforce_headers( - headers, name="headers" - ) - self.stream: typing.Iterable[bytes] | typing.AsyncIterable[bytes] = ( - enforce_stream(content, name="content") - ) - self.extensions = {} if extensions is None else extensions - - if "target" in self.extensions: - self.url = URL( - scheme=self.url.scheme, - host=self.url.host, - port=self.url.port, - target=self.extensions["target"], - ) - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.method!r}]>" - - -class Response: - """ - An HTTP response. - """ - - def __init__( - self, - status: int, - *, - headers: HeaderTypes = None, - content: bytes - | typing.Iterable[bytes] - | typing.AsyncIterable[bytes] - | None = None, - extensions: Extensions | None = None, - ) -> None: - """ - Parameters: - status: The HTTP status code of the response. For example `200`. - headers: The HTTP response headers. - content: The content of the response body. - extensions: A dictionary of optional extra information included on - the responseself.Possible keys include `"http_version"`, - `"reason_phrase"`, and `"network_stream"`. - """ - self.status: int = status - self.headers: list[tuple[bytes, bytes]] = enforce_headers( - headers, name="headers" - ) - self.stream: typing.Iterable[bytes] | typing.AsyncIterable[bytes] = ( - enforce_stream(content, name="content") - ) - self.extensions = {} if extensions is None else extensions - - self._stream_consumed = False - - @property - def content(self) -> bytes: - if not hasattr(self, "_content"): - if isinstance(self.stream, typing.Iterable): - raise RuntimeError( - "Attempted to access 'response.content' on a streaming response. " - "Call 'response.read()' first." - ) - else: - raise RuntimeError( - "Attempted to access 'response.content' on a streaming response. " - "Call 'await response.aread()' first." - ) - return self._content - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.status}]>" - - # Sync interface... - - def read(self) -> bytes: - if not isinstance(self.stream, typing.Iterable): # pragma: nocover - raise RuntimeError( - "Attempted to read an asynchronous response using 'response.read()'. " - "You should use 'await response.aread()' instead." - ) - if not hasattr(self, "_content"): - self._content = b"".join([part for part in self.iter_stream()]) - return self._content - - def iter_stream(self) -> typing.Iterator[bytes]: - if not isinstance(self.stream, typing.Iterable): # pragma: nocover - raise RuntimeError( - "Attempted to stream an asynchronous response using 'for ... in " - "response.iter_stream()'. " - "You should use 'async for ... in response.aiter_stream()' instead." - ) - if self._stream_consumed: - raise RuntimeError( - "Attempted to call 'for ... in response.iter_stream()' more than once." - ) - self._stream_consumed = True - for chunk in self.stream: - yield chunk - - def close(self) -> None: - if not isinstance(self.stream, typing.Iterable): # pragma: nocover - raise RuntimeError( - "Attempted to close an asynchronous response using 'response.close()'. " - "You should use 'await response.aclose()' instead." - ) - if hasattr(self.stream, "close"): - self.stream.close() - - # Async interface... - - async def aread(self) -> bytes: - if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover - raise RuntimeError( - "Attempted to read an synchronous response using " - "'await response.aread()'. " - "You should use 'response.read()' instead." - ) - if not hasattr(self, "_content"): - self._content = b"".join([part async for part in self.aiter_stream()]) - return self._content - - async def aiter_stream(self) -> typing.AsyncIterator[bytes]: - if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover - raise RuntimeError( - "Attempted to stream an synchronous response using 'async for ... in " - "response.aiter_stream()'. " - "You should use 'for ... in response.iter_stream()' instead." - ) - if self._stream_consumed: - raise RuntimeError( - "Attempted to call 'async for ... in response.aiter_stream()' " - "more than once." - ) - self._stream_consumed = True - async for chunk in self.stream: - yield chunk - - async def aclose(self) -> None: - if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover - raise RuntimeError( - "Attempted to close a synchronous response using " - "'await response.aclose()'. " - "You should use 'response.close()' instead." - ) - if hasattr(self.stream, "aclose"): - await self.stream.aclose() - - -class Proxy: - def __init__( - self, - url: URL | bytes | str, - auth: tuple[bytes | str, bytes | str] | None = None, - headers: HeadersAsMapping | HeadersAsSequence | None = None, - ssl_context: ssl.SSLContext | None = None, - ): - self.url = enforce_url(url, name="url") - self.headers = enforce_headers(headers, name="headers") - self.ssl_context = ssl_context - - if auth is not None: - username = enforce_bytes(auth[0], name="auth") - password = enforce_bytes(auth[1], name="auth") - userpass = username + b":" + password - authorization = b"Basic " + base64.b64encode(userpass) - self.auth: tuple[bytes, bytes] | None = (username, password) - self.headers = [(b"Proxy-Authorization", authorization)] + self.headers - else: - self.auth = None diff --git a/venv/lib/python3.10/site-packages/httpcore/_ssl.py b/venv/lib/python3.10/site-packages/httpcore/_ssl.py deleted file mode 100644 index c99c5a67945b8a3a3544d481e979c791ab45fe23..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_ssl.py +++ /dev/null @@ -1,9 +0,0 @@ -import ssl - -import certifi - - -def default_ssl_context() -> ssl.SSLContext: - context = ssl.create_default_context() - context.load_verify_locations(certifi.where()) - return context diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__init__.py b/venv/lib/python3.10/site-packages/httpcore/_sync/__init__.py deleted file mode 100644 index b476d76d9a7ff45de8d18ec22d33d6af2982f92e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -from .connection import HTTPConnection -from .connection_pool import ConnectionPool -from .http11 import HTTP11Connection -from .http_proxy import HTTPProxy -from .interfaces import ConnectionInterface - -try: - from .http2 import HTTP2Connection -except ImportError: # pragma: nocover - - class HTTP2Connection: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use http2 support, but the `h2` package is not " - "installed. Use 'pip install httpcore[http2]'." - ) - - -try: - from .socks_proxy import SOCKSProxy -except ImportError: # pragma: nocover - - class SOCKSProxy: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use SOCKS support, but the `socksio` package is not " - "installed. Use 'pip install httpcore[socks]'." - ) - - -__all__ = [ - "HTTPConnection", - "ConnectionPool", - "HTTPProxy", - "HTTP11Connection", - "HTTP2Connection", - "ConnectionInterface", - "SOCKSProxy", -] diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 7c3b1626492ce186e1dcf12847362fdc7bf1a4d6..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/connection.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/connection.cpython-310.pyc deleted file mode 100644 index b3920457253e25a53d25ab5cfa148e876b93c241..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/connection.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/connection_pool.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/connection_pool.cpython-310.pyc deleted file mode 100644 index edde6413f593ca93ef8e6abca59821234b72fb90..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/connection_pool.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http11.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http11.cpython-310.pyc deleted file mode 100644 index e37420b9c48269c3bda2f831e8bac5336d9c3b5a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http11.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http2.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http2.cpython-310.pyc deleted file mode 100644 index 555aff9e6389abf15f2cade34d140895000b917d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http2.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http_proxy.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http_proxy.cpython-310.pyc deleted file mode 100644 index 432f0bce7553b93e84558fe62a84993d549fd838..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/http_proxy.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/interfaces.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/interfaces.cpython-310.pyc deleted file mode 100644 index 615ebb81e53ec3be7ef653377dcfdb9238990480..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/interfaces.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/socks_proxy.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/socks_proxy.cpython-310.pyc deleted file mode 100644 index 5728a2c89f25998153c7e50fc600a31c446037db..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpcore/_sync/__pycache__/socks_proxy.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/connection.py b/venv/lib/python3.10/site-packages/httpcore/_sync/connection.py deleted file mode 100644 index 363f8be819d2576ea65365e625dd1596ea40429a..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/connection.py +++ /dev/null @@ -1,222 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -import ssl -import types -import typing - -from .._backends.sync import SyncBackend -from .._backends.base import SOCKET_OPTION, NetworkBackend, NetworkStream -from .._exceptions import ConnectError, ConnectTimeout -from .._models import Origin, Request, Response -from .._ssl import default_ssl_context -from .._synchronization import Lock -from .._trace import Trace -from .http11 import HTTP11Connection -from .interfaces import ConnectionInterface - -RETRIES_BACKOFF_FACTOR = 0.5 # 0s, 0.5s, 1s, 2s, 4s, etc. - - -logger = logging.getLogger("httpcore.connection") - - -def exponential_backoff(factor: float) -> typing.Iterator[float]: - """ - Generate a geometric sequence that has a ratio of 2 and starts with 0. - - For example: - - `factor = 2`: `0, 2, 4, 8, 16, 32, 64, ...` - - `factor = 3`: `0, 3, 6, 12, 24, 48, 96, ...` - """ - yield 0 - for n in itertools.count(): - yield factor * 2**n - - -class HTTPConnection(ConnectionInterface): - def __init__( - self, - origin: Origin, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._origin = origin - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend: NetworkBackend = ( - SyncBackend() if network_backend is None else network_backend - ) - self._connection: ConnectionInterface | None = None - self._connect_failed: bool = False - self._request_lock = Lock() - self._socket_options = socket_options - - def handle_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection to {self._origin}" - ) - - try: - with self._request_lock: - if self._connection is None: - stream = self._connect(request) - - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import HTTP2Connection - - self._connection = HTTP2Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = HTTP11Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except BaseException as exc: - self._connect_failed = True - raise exc - - return self._connection.handle_request(request) - - def _connect(self, request: Request) -> NetworkStream: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - retries_left = self._retries - delays = exponential_backoff(factor=RETRIES_BACKOFF_FACTOR) - - while True: - try: - if self._uds is None: - kwargs = { - "host": self._origin.host.decode("ascii"), - "port": self._origin.port, - "local_address": self._local_address, - "timeout": timeout, - "socket_options": self._socket_options, - } - with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - else: - kwargs = { - "path": self._uds, - "timeout": timeout, - "socket_options": self._socket_options, - } - with Trace( - "connect_unix_socket", logger, request, kwargs - ) as trace: - stream = self._network_backend.connect_unix_socket( - **kwargs - ) - trace.return_value = stream - - if self._origin.scheme in (b"https", b"wss"): - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._origin.host.decode("ascii"), - "timeout": timeout, - } - with Trace("start_tls", logger, request, kwargs) as trace: - stream = stream.start_tls(**kwargs) - trace.return_value = stream - return stream - except (ConnectError, ConnectTimeout): - if retries_left <= 0: - raise - retries_left -= 1 - delay = next(delays) - with Trace("retry", logger, request, kwargs) as trace: - self._network_backend.sleep(delay) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def close(self) -> None: - if self._connection is not None: - with Trace("close", logger, None, {}): - self._connection.close() - - def is_available(self) -> bool: - if self._connection is None: - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - def __enter__(self) -> HTTPConnection: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py b/venv/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py deleted file mode 100644 index 9ccfa53e597a29ee387f9d16f3af4f695ac0d33a..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py +++ /dev/null @@ -1,420 +0,0 @@ -from __future__ import annotations - -import ssl -import sys -import types -import typing - -from .._backends.sync import SyncBackend -from .._backends.base import SOCKET_OPTION, NetworkBackend -from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol -from .._models import Origin, Proxy, Request, Response -from .._synchronization import Event, ShieldCancellation, ThreadLock -from .connection import HTTPConnection -from .interfaces import ConnectionInterface, RequestInterface - - -class PoolRequest: - def __init__(self, request: Request) -> None: - self.request = request - self.connection: ConnectionInterface | None = None - self._connection_acquired = Event() - - def assign_to_connection(self, connection: ConnectionInterface | None) -> None: - self.connection = connection - self._connection_acquired.set() - - def clear_connection(self) -> None: - self.connection = None - self._connection_acquired = Event() - - def wait_for_connection( - self, timeout: float | None = None - ) -> ConnectionInterface: - if self.connection is None: - self._connection_acquired.wait(timeout=timeout) - assert self.connection is not None - return self.connection - - def is_queued(self) -> bool: - return self.connection is None - - -class ConnectionPool(RequestInterface): - """ - A connection pool for making HTTP requests. - """ - - def __init__( - self, - ssl_context: ssl.SSLContext | None = None, - proxy: Proxy | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish a - connection. - local_address: Local address to connect from. Can also be used to connect - using a particular address family. Using `local_address="0.0.0.0"` - will connect using an `AF_INET` address (IPv4), while using - `local_address="::"` will connect using an `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - socket_options: Socket options that have to be included - in the TCP socket when the connection was established. - """ - self._ssl_context = ssl_context - self._proxy = proxy - self._max_connections = ( - sys.maxsize if max_connections is None else max_connections - ) - self._max_keepalive_connections = ( - sys.maxsize - if max_keepalive_connections is None - else max_keepalive_connections - ) - self._max_keepalive_connections = min( - self._max_connections, self._max_keepalive_connections - ) - - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend = ( - SyncBackend() if network_backend is None else network_backend - ) - self._socket_options = socket_options - - # The mutable state on a connection pool is the queue of incoming requests, - # and the set of connections that are servicing those requests. - self._connections: list[ConnectionInterface] = [] - self._requests: list[PoolRequest] = [] - - # We only mutate the state of the connection pool within an 'optional_thread_lock' - # context. This holds a threading lock unless we're running in async mode, - # in which case it is a no-op. - self._optional_thread_lock = ThreadLock() - - def create_connection(self, origin: Origin) -> ConnectionInterface: - if self._proxy is not None: - if self._proxy.url.scheme in (b"socks5", b"socks5h"): - from .socks_proxy import Socks5Connection - - return Socks5Connection( - proxy_origin=self._proxy.url.origin, - proxy_auth=self._proxy.auth, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - elif origin.scheme == b"http": - from .http_proxy import ForwardHTTPConnection - - return ForwardHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - ) - from .http_proxy import TunnelHTTPConnection - - return TunnelHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - return HTTPConnection( - origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - retries=self._retries, - local_address=self._local_address, - uds=self._uds, - network_backend=self._network_backend, - socket_options=self._socket_options, - ) - - @property - def connections(self) -> list[ConnectionInterface]: - """ - Return a list of the connections currently in the pool. - - For example: - - ```python - >>> pool.connections - [ - , - , - , - ] - ``` - """ - return list(self._connections) - - def handle_request(self, request: Request) -> Response: - """ - Send an HTTP request, and return an HTTP response. - - This is the core implementation that is called into by `.request()` or `.stream()`. - """ - scheme = request.url.scheme.decode() - if scheme == "": - raise UnsupportedProtocol( - "Request URL is missing an 'http://' or 'https://' protocol." - ) - if scheme not in ("http", "https", "ws", "wss"): - raise UnsupportedProtocol( - f"Request URL has an unsupported protocol '{scheme}://'." - ) - - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("pool", None) - - with self._optional_thread_lock: - # Add the incoming request to our request queue. - pool_request = PoolRequest(request) - self._requests.append(pool_request) - - try: - while True: - with self._optional_thread_lock: - # Assign incoming requests to available connections, - # closing or creating new connections as required. - closing = self._assign_requests_to_connections() - self._close_connections(closing) - - # Wait until this request has an assigned connection. - connection = pool_request.wait_for_connection(timeout=timeout) - - try: - # Send the request on the assigned connection. - response = connection.handle_request( - pool_request.request - ) - except ConnectionNotAvailable: - # In some cases a connection may initially be available to - # handle a request, but then become unavailable. - # - # In this case we clear the connection and try again. - pool_request.clear_connection() - else: - break # pragma: nocover - - except BaseException as exc: - with self._optional_thread_lock: - # For any exception or cancellation we remove the request from - # the queue, and then re-assign requests to connections. - self._requests.remove(pool_request) - closing = self._assign_requests_to_connections() - - self._close_connections(closing) - raise exc from None - - # Return the response. Note that in this case we still have to manage - # the point at which the response is closed. - assert isinstance(response.stream, typing.Iterable) - return Response( - status=response.status, - headers=response.headers, - content=PoolByteStream( - stream=response.stream, pool_request=pool_request, pool=self - ), - extensions=response.extensions, - ) - - def _assign_requests_to_connections(self) -> list[ConnectionInterface]: - """ - Manage the state of the connection pool, assigning incoming - requests to connections as available. - - Called whenever a new request is added or removed from the pool. - - Any closing connections are returned, allowing the I/O for closing - those connections to be handled seperately. - """ - closing_connections = [] - - # First we handle cleaning up any connections that are closed, - # have expired their keep-alive, or surplus idle connections. - for connection in list(self._connections): - if connection.is_closed(): - # log: "removing closed connection" - self._connections.remove(connection) - elif connection.has_expired(): - # log: "closing expired connection" - self._connections.remove(connection) - closing_connections.append(connection) - elif ( - connection.is_idle() - and len([connection.is_idle() for connection in self._connections]) - > self._max_keepalive_connections - ): - # log: "closing idle connection" - self._connections.remove(connection) - closing_connections.append(connection) - - # Assign queued requests to connections. - queued_requests = [request for request in self._requests if request.is_queued()] - for pool_request in queued_requests: - origin = pool_request.request.url.origin - available_connections = [ - connection - for connection in self._connections - if connection.can_handle_request(origin) and connection.is_available() - ] - idle_connections = [ - connection for connection in self._connections if connection.is_idle() - ] - - # There are three cases for how we may be able to handle the request: - # - # 1. There is an existing connection that can handle the request. - # 2. We can create a new connection to handle the request. - # 3. We can close an idle connection and then create a new connection - # to handle the request. - if available_connections: - # log: "reusing existing connection" - connection = available_connections[0] - pool_request.assign_to_connection(connection) - elif len(self._connections) < self._max_connections: - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - elif idle_connections: - # log: "closing idle connection" - connection = idle_connections[0] - self._connections.remove(connection) - closing_connections.append(connection) - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - - return closing_connections - - def _close_connections(self, closing: list[ConnectionInterface]) -> None: - # Close connections which have been removed from the pool. - with ShieldCancellation(): - for connection in closing: - connection.close() - - def close(self) -> None: - # Explicitly close the connection pool. - # Clears all existing requests and connections. - with self._optional_thread_lock: - closing_connections = list(self._connections) - self._connections = [] - self._close_connections(closing_connections) - - def __enter__(self) -> ConnectionPool: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - with self._optional_thread_lock: - request_is_queued = [request.is_queued() for request in self._requests] - connection_is_idle = [ - connection.is_idle() for connection in self._connections - ] - - num_active_requests = request_is_queued.count(False) - num_queued_requests = request_is_queued.count(True) - num_active_connections = connection_is_idle.count(False) - num_idle_connections = connection_is_idle.count(True) - - requests_info = ( - f"Requests: {num_active_requests} active, {num_queued_requests} queued" - ) - connection_info = ( - f"Connections: {num_active_connections} active, {num_idle_connections} idle" - ) - - return f"<{class_name} [{requests_info} | {connection_info}]>" - - -class PoolByteStream: - def __init__( - self, - stream: typing.Iterable[bytes], - pool_request: PoolRequest, - pool: ConnectionPool, - ) -> None: - self._stream = stream - self._pool_request = pool_request - self._pool = pool - self._closed = False - - def __iter__(self) -> typing.Iterator[bytes]: - try: - for part in self._stream: - yield part - except BaseException as exc: - self.close() - raise exc from None - - def close(self) -> None: - if not self._closed: - self._closed = True - with ShieldCancellation(): - if hasattr(self._stream, "close"): - self._stream.close() - - with self._pool._optional_thread_lock: - self._pool._requests.remove(self._pool_request) - closing = self._pool._assign_requests_to_connections() - - self._pool._close_connections(closing) diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/http11.py b/venv/lib/python3.10/site-packages/httpcore/_sync/http11.py deleted file mode 100644 index ebd3a97480c720d418acb1285a7b75da19b62c8c..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/http11.py +++ /dev/null @@ -1,379 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import ssl -import time -import types -import typing - -import h11 - -from .._backends.base import NetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, - WriteError, - map_exceptions, -) -from .._models import Origin, Request, Response -from .._synchronization import Lock, ShieldCancellation -from .._trace import Trace -from .interfaces import ConnectionInterface - -logger = logging.getLogger("httpcore.http11") - - -# A subset of `h11.Event` types supported by `_send_event` -H11SendEvent = typing.Union[ - h11.Request, - h11.Data, - h11.EndOfMessage, -] - - -class HTTPConnectionState(enum.IntEnum): - NEW = 0 - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class HTTP11Connection(ConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - MAX_INCOMPLETE_EVENT_SIZE = 100 * 1024 - - def __init__( - self, - origin: Origin, - stream: NetworkStream, - keepalive_expiry: float | None = None, - ) -> None: - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._expire_at: float | None = None - self._state = HTTPConnectionState.NEW - self._state_lock = Lock() - self._request_count = 0 - self._h11_state = h11.Connection( - our_role=h11.CLIENT, - max_incomplete_event_size=self.MAX_INCOMPLETE_EVENT_SIZE, - ) - - def handle_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - with self._state_lock: - if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): - self._request_count += 1 - self._state = HTTPConnectionState.ACTIVE - self._expire_at = None - else: - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request} - try: - with Trace( - "send_request_headers", logger, request, kwargs - ) as trace: - self._send_request_headers(**kwargs) - with Trace("send_request_body", logger, request, kwargs) as trace: - self._send_request_body(**kwargs) - except WriteError: - # If we get a write error while we're writing the request, - # then we supress this error and move on to attempting to - # read the response. Servers can sometimes close the request - # pre-emptively and then respond with a well formed HTTP - # error response. - pass - - with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - ( - http_version, - status, - reason_phrase, - headers, - trailing_data, - ) = self._receive_response_headers(**kwargs) - trace.return_value = ( - http_version, - status, - reason_phrase, - headers, - ) - - network_stream = self._network_stream - - # CONNECT or Upgrade request - if (status == 101) or ( - (request.method == b"CONNECT") and (200 <= status < 300) - ): - network_stream = HTTP11UpgradeStream(network_stream, trailing_data) - - return Response( - status=status, - headers=headers, - content=HTTP11ConnectionByteStream(self, request), - extensions={ - "http_version": http_version, - "reason_phrase": reason_phrase, - "network_stream": network_stream, - }, - ) - except BaseException as exc: - with ShieldCancellation(): - with Trace("response_closed", logger, request) as trace: - self._response_closed() - raise exc - - # Sending the request... - - def _send_request_headers(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - with map_exceptions({h11.LocalProtocolError: LocalProtocolError}): - event = h11.Request( - method=request.method, - target=request.url.target, - headers=request.headers, - ) - self._send_event(event, timeout=timeout) - - def _send_request_body(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - assert isinstance(request.stream, typing.Iterable) - for chunk in request.stream: - event = h11.Data(data=chunk) - self._send_event(event, timeout=timeout) - - self._send_event(h11.EndOfMessage(), timeout=timeout) - - def _send_event(self, event: h11.Event, timeout: float | None = None) -> None: - bytes_to_send = self._h11_state.send(event) - if bytes_to_send is not None: - self._network_stream.write(bytes_to_send, timeout=timeout) - - # Receiving the response... - - def _receive_response_headers( - self, request: Request - ) -> tuple[bytes, int, bytes, list[tuple[bytes, bytes]], bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = self._receive_event(timeout=timeout) - if isinstance(event, h11.Response): - break - if ( - isinstance(event, h11.InformationalResponse) - and event.status_code == 101 - ): - break - - http_version = b"HTTP/" + event.http_version - - # h11 version 0.11+ supports a `raw_items` interface to get the - # raw header casing, rather than the enforced lowercase headers. - headers = event.headers.raw_items() - - trailing_data, _ = self._h11_state.trailing_data - - return http_version, event.status_code, event.reason, headers, trailing_data - - def _receive_response_body( - self, request: Request - ) -> typing.Iterator[bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = self._receive_event(timeout=timeout) - if isinstance(event, h11.Data): - yield bytes(event.data) - elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): - break - - def _receive_event( - self, timeout: float | None = None - ) -> h11.Event | type[h11.PAUSED]: - while True: - with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): - event = self._h11_state.next_event() - - if event is h11.NEED_DATA: - data = self._network_stream.read( - self.READ_NUM_BYTES, timeout=timeout - ) - - # If we feed this case through h11 we'll raise an exception like: - # - # httpcore.RemoteProtocolError: can't handle event type - # ConnectionClosed when role=SERVER and state=SEND_RESPONSE - # - # Which is accurate, but not very informative from an end-user - # perspective. Instead we handle this case distinctly and treat - # it as a ConnectError. - if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: - msg = "Server disconnected without sending a response." - raise RemoteProtocolError(msg) - - self._h11_state.receive_data(data) - else: - # mypy fails to narrow the type in the above if statement above - return event # type: ignore[return-value] - - def _response_closed(self) -> None: - with self._state_lock: - if ( - self._h11_state.our_state is h11.DONE - and self._h11_state.their_state is h11.DONE - ): - self._state = HTTPConnectionState.IDLE - self._h11_state.start_next_cycle() - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - else: - self.close() - - # Once the connection is no longer required... - - def close(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._state = HTTPConnectionState.CLOSED - self._network_stream.close() - - # The ConnectionInterface methods provide information about the state of - # the connection, allowing for a connection pooling implementation to - # determine when to reuse and when to close the connection... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - # Note that HTTP/1.1 connections in the "NEW" state are not treated as - # being "available". The control flow which created the connection will - # be able to send an outgoing request, but the connection will not be - # acquired from the connection pool for any other request. - return self._state == HTTPConnectionState.IDLE - - def has_expired(self) -> bool: - now = time.monotonic() - keepalive_expired = self._expire_at is not None and now > self._expire_at - - # If the HTTP connection is idle but the socket is readable, then the - # only valid state is that the socket is about to return b"", indicating - # a server-initiated disconnect. - server_disconnected = ( - self._state == HTTPConnectionState.IDLE - and self._network_stream.get_extra_info("is_readable") - ) - - return keepalive_expired or server_disconnected - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/1.1, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - def __enter__(self) -> HTTP11Connection: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() - - -class HTTP11ConnectionByteStream: - def __init__(self, connection: HTTP11Connection, request: Request) -> None: - self._connection = connection - self._request = request - self._closed = False - - def __iter__(self) -> typing.Iterator[bytes]: - kwargs = {"request": self._request} - try: - with Trace("receive_response_body", logger, self._request, kwargs): - for chunk in self._connection._receive_response_body(**kwargs): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with ShieldCancellation(): - self.close() - raise exc - - def close(self) -> None: - if not self._closed: - self._closed = True - with Trace("response_closed", logger, self._request): - self._connection._response_closed() - - -class HTTP11UpgradeStream(NetworkStream): - def __init__(self, stream: NetworkStream, leading_data: bytes) -> None: - self._stream = stream - self._leading_data = leading_data - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._leading_data: - buffer = self._leading_data[:max_bytes] - self._leading_data = self._leading_data[max_bytes:] - return buffer - else: - return self._stream.read(max_bytes, timeout) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - self._stream.write(buffer, timeout) - - def close(self) -> None: - self._stream.close() - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - return self._stream.start_tls(ssl_context, server_hostname, timeout) - - def get_extra_info(self, info: str) -> typing.Any: - return self._stream.get_extra_info(info) diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/http2.py b/venv/lib/python3.10/site-packages/httpcore/_sync/http2.py deleted file mode 100644 index ddcc189001c50c37c6a03810dc21d955df919f10..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/http2.py +++ /dev/null @@ -1,592 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import time -import types -import typing - -import h2.config -import h2.connection -import h2.events -import h2.exceptions -import h2.settings - -from .._backends.base import NetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, -) -from .._models import Origin, Request, Response -from .._synchronization import Lock, Semaphore, ShieldCancellation -from .._trace import Trace -from .interfaces import ConnectionInterface - -logger = logging.getLogger("httpcore.http2") - - -def has_body_headers(request: Request) -> bool: - return any( - k.lower() == b"content-length" or k.lower() == b"transfer-encoding" - for k, v in request.headers - ) - - -class HTTPConnectionState(enum.IntEnum): - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class HTTP2Connection(ConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - CONFIG = h2.config.H2Configuration(validate_inbound_headers=False) - - def __init__( - self, - origin: Origin, - stream: NetworkStream, - keepalive_expiry: float | None = None, - ): - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._h2_state = h2.connection.H2Connection(config=self.CONFIG) - self._state = HTTPConnectionState.IDLE - self._expire_at: float | None = None - self._request_count = 0 - self._init_lock = Lock() - self._state_lock = Lock() - self._read_lock = Lock() - self._write_lock = Lock() - self._sent_connection_init = False - self._used_all_stream_ids = False - self._connection_error = False - - # Mapping from stream ID to response stream events. - self._events: dict[ - int, - list[ - h2.events.ResponseReceived - | h2.events.DataReceived - | h2.events.StreamEnded - | h2.events.StreamReset, - ], - ] = {} - - # Connection terminated events are stored as state since - # we need to handle them for all streams. - self._connection_terminated: h2.events.ConnectionTerminated | None = None - - self._read_exception: Exception | None = None - self._write_exception: Exception | None = None - - def handle_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - # This cannot occur in normal operation, since the connection pool - # will only send requests on connections that handle them. - # It's in place simply for resilience as a guard against incorrect - # usage, for anyone working directly with httpcore connections. - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - with self._state_lock: - if self._state in (HTTPConnectionState.ACTIVE, HTTPConnectionState.IDLE): - self._request_count += 1 - self._expire_at = None - self._state = HTTPConnectionState.ACTIVE - else: - raise ConnectionNotAvailable() - - with self._init_lock: - if not self._sent_connection_init: - try: - sci_kwargs = {"request": request} - with Trace( - "send_connection_init", logger, request, sci_kwargs - ): - self._send_connection_init(**sci_kwargs) - except BaseException as exc: - with ShieldCancellation(): - self.close() - raise exc - - self._sent_connection_init = True - - # Initially start with just 1 until the remote server provides - # its max_concurrent_streams value - self._max_streams = 1 - - local_settings_max_streams = ( - self._h2_state.local_settings.max_concurrent_streams - ) - self._max_streams_semaphore = Semaphore(local_settings_max_streams) - - for _ in range(local_settings_max_streams - self._max_streams): - self._max_streams_semaphore.acquire() - - self._max_streams_semaphore.acquire() - - try: - stream_id = self._h2_state.get_next_available_stream_id() - self._events[stream_id] = [] - except h2.exceptions.NoAvailableStreamIDError: # pragma: nocover - self._used_all_stream_ids = True - self._request_count -= 1 - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request, "stream_id": stream_id} - with Trace("send_request_headers", logger, request, kwargs): - self._send_request_headers(request=request, stream_id=stream_id) - with Trace("send_request_body", logger, request, kwargs): - self._send_request_body(request=request, stream_id=stream_id) - with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - status, headers = self._receive_response( - request=request, stream_id=stream_id - ) - trace.return_value = (status, headers) - - return Response( - status=status, - headers=headers, - content=HTTP2ConnectionByteStream(self, request, stream_id=stream_id), - extensions={ - "http_version": b"HTTP/2", - "network_stream": self._network_stream, - "stream_id": stream_id, - }, - ) - except BaseException as exc: # noqa: PIE786 - with ShieldCancellation(): - kwargs = {"stream_id": stream_id} - with Trace("response_closed", logger, request, kwargs): - self._response_closed(stream_id=stream_id) - - if isinstance(exc, h2.exceptions.ProtocolError): - # One case where h2 can raise a protocol error is when a - # closed frame has been seen by the state machine. - # - # This happens when one stream is reading, and encounters - # a GOAWAY event. Other flows of control may then raise - # a protocol error at any point they interact with the 'h2_state'. - # - # In this case we'll have stored the event, and should raise - # it as a RemoteProtocolError. - if self._connection_terminated: # pragma: nocover - raise RemoteProtocolError(self._connection_terminated) - # If h2 raises a protocol error in some other state then we - # must somehow have made a protocol violation. - raise LocalProtocolError(exc) # pragma: nocover - - raise exc - - def _send_connection_init(self, request: Request) -> None: - """ - The HTTP/2 connection requires some initial setup before we can start - using individual request/response streams on it. - """ - # Need to set these manually here instead of manipulating via - # __setitem__() otherwise the H2Connection will emit SettingsUpdate - # frames in addition to sending the undesired defaults. - self._h2_state.local_settings = h2.settings.Settings( - client=True, - initial_values={ - # Disable PUSH_PROMISE frames from the server since we don't do anything - # with them for now. Maybe when we support caching? - h2.settings.SettingCodes.ENABLE_PUSH: 0, - # These two are taken from h2 for safe defaults - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100, - h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 65536, - }, - ) - - # Some websites (*cough* Yahoo *cough*) balk at this setting being - # present in the initial handshake since it's not defined in the original - # RFC despite the RFC mandating ignoring settings you don't know about. - del self._h2_state.local_settings[ - h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL - ] - - self._h2_state.initiate_connection() - self._h2_state.increment_flow_control_window(2**24) - self._write_outgoing_data(request) - - # Sending the request... - - def _send_request_headers(self, request: Request, stream_id: int) -> None: - """ - Send the request headers to a given stream ID. - """ - end_stream = not has_body_headers(request) - - # In HTTP/2 the ':authority' pseudo-header is used instead of 'Host'. - # In order to gracefully handle HTTP/1.1 and HTTP/2 we always require - # HTTP/1.1 style headers, and map them appropriately if we end up on - # an HTTP/2 connection. - authority = [v for k, v in request.headers if k.lower() == b"host"][0] - - headers = [ - (b":method", request.method), - (b":authority", authority), - (b":scheme", request.url.scheme), - (b":path", request.url.target), - ] + [ - (k.lower(), v) - for k, v in request.headers - if k.lower() - not in ( - b"host", - b"transfer-encoding", - ) - ] - - self._h2_state.send_headers(stream_id, headers, end_stream=end_stream) - self._h2_state.increment_flow_control_window(2**24, stream_id=stream_id) - self._write_outgoing_data(request) - - def _send_request_body(self, request: Request, stream_id: int) -> None: - """ - Iterate over the request body sending it to a given stream ID. - """ - if not has_body_headers(request): - return - - assert isinstance(request.stream, typing.Iterable) - for data in request.stream: - self._send_stream_data(request, stream_id, data) - self._send_end_stream(request, stream_id) - - def _send_stream_data( - self, request: Request, stream_id: int, data: bytes - ) -> None: - """ - Send a single chunk of data in one or more data frames. - """ - while data: - max_flow = self._wait_for_outgoing_flow(request, stream_id) - chunk_size = min(len(data), max_flow) - chunk, data = data[:chunk_size], data[chunk_size:] - self._h2_state.send_data(stream_id, chunk) - self._write_outgoing_data(request) - - def _send_end_stream(self, request: Request, stream_id: int) -> None: - """ - Send an empty data frame on on a given stream ID with the END_STREAM flag set. - """ - self._h2_state.end_stream(stream_id) - self._write_outgoing_data(request) - - # Receiving the response... - - def _receive_response( - self, request: Request, stream_id: int - ) -> tuple[int, list[tuple[bytes, bytes]]]: - """ - Return the response status code and headers for a given stream ID. - """ - while True: - event = self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.ResponseReceived): - break - - status_code = 200 - headers = [] - assert event.headers is not None - for k, v in event.headers: - if k == b":status": - status_code = int(v.decode("ascii", errors="ignore")) - elif not k.startswith(b":"): - headers.append((k, v)) - - return (status_code, headers) - - def _receive_response_body( - self, request: Request, stream_id: int - ) -> typing.Iterator[bytes]: - """ - Iterator that returns the bytes of the response body for a given stream ID. - """ - while True: - event = self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.DataReceived): - assert event.flow_controlled_length is not None - assert event.data is not None - amount = event.flow_controlled_length - self._h2_state.acknowledge_received_data(amount, stream_id) - self._write_outgoing_data(request) - yield event.data - elif isinstance(event, h2.events.StreamEnded): - break - - def _receive_stream_event( - self, request: Request, stream_id: int - ) -> h2.events.ResponseReceived | h2.events.DataReceived | h2.events.StreamEnded: - """ - Return the next available event for a given stream ID. - - Will read more data from the network if required. - """ - while not self._events.get(stream_id): - self._receive_events(request, stream_id) - event = self._events[stream_id].pop(0) - if isinstance(event, h2.events.StreamReset): - raise RemoteProtocolError(event) - return event - - def _receive_events( - self, request: Request, stream_id: int | None = None - ) -> None: - """ - Read some data from the network until we see one or more events - for a given stream ID. - """ - with self._read_lock: - if self._connection_terminated is not None: - last_stream_id = self._connection_terminated.last_stream_id - if stream_id and last_stream_id and stream_id > last_stream_id: - self._request_count -= 1 - raise ConnectionNotAvailable() - raise RemoteProtocolError(self._connection_terminated) - - # This conditional is a bit icky. We don't want to block reading if we've - # actually got an event to return for a given stream. We need to do that - # check *within* the atomic read lock. Though it also need to be optional, - # because when we call it from `_wait_for_outgoing_flow` we *do* want to - # block until we've available flow control, event when we have events - # pending for the stream ID we're attempting to send on. - if stream_id is None or not self._events.get(stream_id): - events = self._read_incoming_data(request) - for event in events: - if isinstance(event, h2.events.RemoteSettingsChanged): - with Trace( - "receive_remote_settings", logger, request - ) as trace: - self._receive_remote_settings_change(event) - trace.return_value = event - - elif isinstance( - event, - ( - h2.events.ResponseReceived, - h2.events.DataReceived, - h2.events.StreamEnded, - h2.events.StreamReset, - ), - ): - if event.stream_id in self._events: - self._events[event.stream_id].append(event) - - elif isinstance(event, h2.events.ConnectionTerminated): - self._connection_terminated = event - - self._write_outgoing_data(request) - - def _receive_remote_settings_change( - self, event: h2.events.RemoteSettingsChanged - ) -> None: - max_concurrent_streams = event.changed_settings.get( - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS - ) - if max_concurrent_streams: - new_max_streams = min( - max_concurrent_streams.new_value, - self._h2_state.local_settings.max_concurrent_streams, - ) - if new_max_streams and new_max_streams != self._max_streams: - while new_max_streams > self._max_streams: - self._max_streams_semaphore.release() - self._max_streams += 1 - while new_max_streams < self._max_streams: - self._max_streams_semaphore.acquire() - self._max_streams -= 1 - - def _response_closed(self, stream_id: int) -> None: - self._max_streams_semaphore.release() - del self._events[stream_id] - with self._state_lock: - if self._connection_terminated and not self._events: - self.close() - - elif self._state == HTTPConnectionState.ACTIVE and not self._events: - self._state = HTTPConnectionState.IDLE - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - if self._used_all_stream_ids: # pragma: nocover - self.close() - - def close(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._h2_state.close_connection() - self._state = HTTPConnectionState.CLOSED - self._network_stream.close() - - # Wrappers around network read/write operations... - - def _read_incoming_data(self, request: Request) -> list[h2.events.Event]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - if self._read_exception is not None: - raise self._read_exception # pragma: nocover - - try: - data = self._network_stream.read(self.READ_NUM_BYTES, timeout) - if data == b"": - raise RemoteProtocolError("Server disconnected") - except Exception as exc: - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future reads. - # (For example, this means that a single read timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._read_exception = exc - self._connection_error = True - raise exc - - events: list[h2.events.Event] = self._h2_state.receive_data(data) - - return events - - def _write_outgoing_data(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - with self._write_lock: - data_to_send = self._h2_state.data_to_send() - - if self._write_exception is not None: - raise self._write_exception # pragma: nocover - - try: - self._network_stream.write(data_to_send, timeout) - except Exception as exc: # pragma: nocover - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future write. - # (For example, this means that a single write timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._write_exception = exc - self._connection_error = True - raise exc - - # Flow control... - - def _wait_for_outgoing_flow(self, request: Request, stream_id: int) -> int: - """ - Returns the maximum allowable outgoing flow for a given stream. - - If the allowable flow is zero, then waits on the network until - WindowUpdated frames have increased the flow rate. - https://tools.ietf.org/html/rfc7540#section-6.9 - """ - local_flow: int = self._h2_state.local_flow_control_window(stream_id) - max_frame_size: int = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - while flow == 0: - self._receive_events(request) - local_flow = self._h2_state.local_flow_control_window(stream_id) - max_frame_size = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - return flow - - # Interface for connection pooling... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - return ( - self._state != HTTPConnectionState.CLOSED - and not self._connection_error - and not self._used_all_stream_ids - and not ( - self._h2_state.state_machine.state - == h2.connection.ConnectionState.CLOSED - ) - ) - - def has_expired(self) -> bool: - now = time.monotonic() - return self._expire_at is not None and now > self._expire_at - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/2, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - def __enter__(self) -> HTTP2Connection: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() - - -class HTTP2ConnectionByteStream: - def __init__( - self, connection: HTTP2Connection, request: Request, stream_id: int - ) -> None: - self._connection = connection - self._request = request - self._stream_id = stream_id - self._closed = False - - def __iter__(self) -> typing.Iterator[bytes]: - kwargs = {"request": self._request, "stream_id": self._stream_id} - try: - with Trace("receive_response_body", logger, self._request, kwargs): - for chunk in self._connection._receive_response_body( - request=self._request, stream_id=self._stream_id - ): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with ShieldCancellation(): - self.close() - raise exc - - def close(self) -> None: - if not self._closed: - self._closed = True - kwargs = {"stream_id": self._stream_id} - with Trace("response_closed", logger, self._request, kwargs): - self._connection._response_closed(stream_id=self._stream_id) diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/http_proxy.py b/venv/lib/python3.10/site-packages/httpcore/_sync/http_proxy.py deleted file mode 100644 index ecca88f7dc93b78f2aa26f16cf29d17a8a83ae27..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/http_proxy.py +++ /dev/null @@ -1,367 +0,0 @@ -from __future__ import annotations - -import base64 -import logging -import ssl -import typing - -from .._backends.base import SOCKET_OPTION, NetworkBackend -from .._exceptions import ProxyError -from .._models import ( - URL, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, -) -from .._ssl import default_ssl_context -from .._synchronization import Lock -from .._trace import Trace -from .connection import HTTPConnection -from .connection_pool import ConnectionPool -from .http11 import HTTP11Connection -from .interfaces import ConnectionInterface - -ByteOrStr = typing.Union[bytes, str] -HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] -HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] - - -logger = logging.getLogger("httpcore.proxy") - - -def merge_headers( - default_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - override_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, -) -> list[tuple[bytes, bytes]]: - """ - Append default_headers and override_headers, de-duplicating if a key exists - in both cases. - """ - default_headers = [] if default_headers is None else list(default_headers) - override_headers = [] if override_headers is None else list(override_headers) - has_override = set(key.lower() for key, value in override_headers) - default_headers = [ - (key, value) - for key, value in default_headers - if key.lower() not in has_override - ] - return default_headers + override_headers - - -class HTTPProxy(ConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - proxy_auth: Any proxy authentication as a two-tuple of - (username, password). May be either bytes or ascii-only str. - proxy_headers: Any HTTP headers to use for the proxy requests. - For example `{"Proxy-Authorization": "Basic :"}`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - proxy_ssl_context: The same as `ssl_context`, but for a proxy server rather than a remote origin. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - local_address=local_address, - uds=uds, - socket_options=socket_options, - ) - - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if ( - self._proxy_url.scheme == b"http" and proxy_ssl_context is not None - ): # pragma: no cover - raise RuntimeError( - "The `proxy_ssl_context` argument is not allowed for the http scheme" - ) - - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - if proxy_auth is not None: - username = enforce_bytes(proxy_auth[0], name="proxy_auth") - password = enforce_bytes(proxy_auth[1], name="proxy_auth") - userpass = username + b":" + password - authorization = b"Basic " + base64.b64encode(userpass) - self._proxy_headers = [ - (b"Proxy-Authorization", authorization) - ] + self._proxy_headers - - def create_connection(self, origin: Origin) -> ConnectionInterface: - if origin.scheme == b"http": - return ForwardHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - proxy_ssl_context=self._proxy_ssl_context, - ) - return TunnelHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - ssl_context=self._ssl_context, - proxy_ssl_context=self._proxy_ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class ForwardHTTPConnection(ConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - keepalive_expiry: float | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - ) -> None: - self._connection = HTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._remote_origin = remote_origin - - def handle_request(self, request: Request) -> Response: - headers = merge_headers(self._proxy_headers, request.headers) - url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=bytes(request.url), - ) - proxy_request = Request( - method=request.method, - url=url, - headers=headers, - content=request.stream, - extensions=request.extensions, - ) - return self._connection.handle_request(proxy_request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - def close(self) -> None: - self._connection.close() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - -class TunnelHTTPConnection(ConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - proxy_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._connection: ConnectionInterface = HTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._connect_lock = Lock() - self._connected = False - - def handle_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("connect", None) - - with self._connect_lock: - if not self._connected: - target = b"%b:%d" % (self._remote_origin.host, self._remote_origin.port) - - connect_url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=target, - ) - connect_headers = merge_headers( - [(b"Host", target), (b"Accept", b"*/*")], self._proxy_headers - ) - connect_request = Request( - method=b"CONNECT", - url=connect_url, - headers=connect_headers, - extensions=request.extensions, - ) - connect_response = self._connection.handle_request( - connect_request - ) - - if connect_response.status < 200 or connect_response.status > 299: - reason_bytes = connect_response.extensions.get("reason_phrase", b"") - reason_str = reason_bytes.decode("ascii", errors="ignore") - msg = "%d %s" % (connect_response.status, reason_str) - self._connection.close() - raise ProxyError(msg) - - stream = connect_response.extensions["network_stream"] - - # Upgrade the stream to SSL - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - with Trace("start_tls", logger, request, kwargs) as trace: - stream = stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import HTTP2Connection - - self._connection = HTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = HTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - - self._connected = True - return self._connection.handle_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - def close(self) -> None: - self._connection.close() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/interfaces.py b/venv/lib/python3.10/site-packages/httpcore/_sync/interfaces.py deleted file mode 100644 index e673d4cc1b1dd7e7ecdbde91fd6ada386c3de03f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/interfaces.py +++ /dev/null @@ -1,137 +0,0 @@ -from __future__ import annotations - -import contextlib -import typing - -from .._models import ( - URL, - Extensions, - HeaderTypes, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, - include_request_headers, -) - - -class RequestInterface: - def request( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> Response: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = self.handle_request(request) - try: - response.read() - finally: - response.close() - return response - - @contextlib.contextmanager - def stream( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> typing.Iterator[Response]: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = self.handle_request(request) - try: - yield response - finally: - response.close() - - def handle_request(self, request: Request) -> Response: - raise NotImplementedError() # pragma: nocover - - -class ConnectionInterface(RequestInterface): - def close(self) -> None: - raise NotImplementedError() # pragma: nocover - - def info(self) -> str: - raise NotImplementedError() # pragma: nocover - - def can_handle_request(self, origin: Origin) -> bool: - raise NotImplementedError() # pragma: nocover - - def is_available(self) -> bool: - """ - Return `True` if the connection is currently able to accept an - outgoing request. - - An HTTP/1.1 connection will only be available if it is currently idle. - - An HTTP/2 connection will be available so long as the stream ID space is - not yet exhausted, and the connection is not in an error state. - - While the connection is being established we may not yet know if it is going - to result in an HTTP/1.1 or HTTP/2 connection. The connection should be - treated as being available, but might ultimately raise `NewConnectionRequired` - required exceptions if multiple requests are attempted over a connection - that ends up being established as HTTP/1.1. - """ - raise NotImplementedError() # pragma: nocover - - def has_expired(self) -> bool: - """ - Return `True` if the connection is in a state where it should be closed. - - This either means that the connection is idle and it has passed the - expiry time on its keep-alive, or that server has sent an EOF. - """ - raise NotImplementedError() # pragma: nocover - - def is_idle(self) -> bool: - """ - Return `True` if the connection is currently idle. - """ - raise NotImplementedError() # pragma: nocover - - def is_closed(self) -> bool: - """ - Return `True` if the connection has been closed. - - Used when a response is closed to determine if the connection may be - returned to the connection pool or not. - """ - raise NotImplementedError() # pragma: nocover diff --git a/venv/lib/python3.10/site-packages/httpcore/_sync/socks_proxy.py b/venv/lib/python3.10/site-packages/httpcore/_sync/socks_proxy.py deleted file mode 100644 index 0ca96ddfb580b19413797f41e79f7abcecdd9d79..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_sync/socks_proxy.py +++ /dev/null @@ -1,341 +0,0 @@ -from __future__ import annotations - -import logging -import ssl - -import socksio - -from .._backends.sync import SyncBackend -from .._backends.base import NetworkBackend, NetworkStream -from .._exceptions import ConnectionNotAvailable, ProxyError -from .._models import URL, Origin, Request, Response, enforce_bytes, enforce_url -from .._ssl import default_ssl_context -from .._synchronization import Lock -from .._trace import Trace -from .connection_pool import ConnectionPool -from .http11 import HTTP11Connection -from .interfaces import ConnectionInterface - -logger = logging.getLogger("httpcore.socks") - - -AUTH_METHODS = { - b"\x00": "NO AUTHENTICATION REQUIRED", - b"\x01": "GSSAPI", - b"\x02": "USERNAME/PASSWORD", - b"\xff": "NO ACCEPTABLE METHODS", -} - -REPLY_CODES = { - b"\x00": "Succeeded", - b"\x01": "General SOCKS server failure", - b"\x02": "Connection not allowed by ruleset", - b"\x03": "Network unreachable", - b"\x04": "Host unreachable", - b"\x05": "Connection refused", - b"\x06": "TTL expired", - b"\x07": "Command not supported", - b"\x08": "Address type not supported", -} - - -def _init_socks5_connection( - stream: NetworkStream, - *, - host: bytes, - port: int, - auth: tuple[bytes, bytes] | None = None, -) -> None: - conn = socksio.socks5.SOCKS5Connection() - - # Auth method request - auth_method = ( - socksio.socks5.SOCKS5AuthMethod.NO_AUTH_REQUIRED - if auth is None - else socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD - ) - conn.send(socksio.socks5.SOCKS5AuthMethodsRequest([auth_method])) - outgoing_bytes = conn.data_to_send() - stream.write(outgoing_bytes) - - # Auth method response - incoming_bytes = stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5AuthReply) - if response.method != auth_method: - requested = AUTH_METHODS.get(auth_method, "UNKNOWN") - responded = AUTH_METHODS.get(response.method, "UNKNOWN") - raise ProxyError( - f"Requested {requested} from proxy server, but got {responded}." - ) - - if response.method == socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD: - # Username/password request - assert auth is not None - username, password = auth - conn.send(socksio.socks5.SOCKS5UsernamePasswordRequest(username, password)) - outgoing_bytes = conn.data_to_send() - stream.write(outgoing_bytes) - - # Username/password response - incoming_bytes = stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5UsernamePasswordReply) - if not response.success: - raise ProxyError("Invalid username/password") - - # Connect request - conn.send( - socksio.socks5.SOCKS5CommandRequest.from_address( - socksio.socks5.SOCKS5Command.CONNECT, (host, port) - ) - ) - outgoing_bytes = conn.data_to_send() - stream.write(outgoing_bytes) - - # Connect response - incoming_bytes = stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5Reply) - if response.reply_code != socksio.socks5.SOCKS5ReplyCode.SUCCEEDED: - reply_code = REPLY_CODES.get(response.reply_code, "UNKOWN") - raise ProxyError(f"Proxy Server could not connect: {reply_code}.") - - -class SOCKSProxy(ConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - network_backend: NetworkBackend | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - ) - self._ssl_context = ssl_context - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if proxy_auth is not None: - username, password = proxy_auth - username_bytes = enforce_bytes(username, name="proxy_auth") - password_bytes = enforce_bytes(password, name="proxy_auth") - self._proxy_auth: tuple[bytes, bytes] | None = ( - username_bytes, - password_bytes, - ) - else: - self._proxy_auth = None - - def create_connection(self, origin: Origin) -> ConnectionInterface: - return Socks5Connection( - proxy_origin=self._proxy_url.origin, - remote_origin=origin, - proxy_auth=self._proxy_auth, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class Socks5Connection(ConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_auth: tuple[bytes, bytes] | None = None, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: NetworkBackend | None = None, - ) -> None: - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._proxy_auth = proxy_auth - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - - self._network_backend: NetworkBackend = ( - SyncBackend() if network_backend is None else network_backend - ) - self._connect_lock = Lock() - self._connection: ConnectionInterface | None = None - self._connect_failed = False - - def handle_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - with self._connect_lock: - if self._connection is None: - try: - # Connect to the proxy - kwargs = { - "host": self._proxy_origin.host.decode("ascii"), - "port": self._proxy_origin.port, - "timeout": timeout, - } - with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - - # Connect to the remote host using socks5 - kwargs = { - "stream": stream, - "host": self._remote_origin.host.decode("ascii"), - "port": self._remote_origin.port, - "auth": self._proxy_auth, - } - with Trace( - "setup_socks5_connection", logger, request, kwargs - ) as trace: - _init_socks5_connection(**kwargs) - trace.return_value = stream - - # Upgrade the stream to SSL - if self._remote_origin.scheme == b"https": - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ( - ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ) - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - with Trace("start_tls", logger, request, kwargs) as trace: - stream = stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or ( - self._http2 and not self._http1 - ): # pragma: nocover - from .http2 import HTTP2Connection - - self._connection = HTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = HTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except Exception as exc: - self._connect_failed = True - raise exc - elif not self._connection.is_available(): # pragma: nocover - raise ConnectionNotAvailable() - - return self._connection.handle_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - def close(self) -> None: - if self._connection is not None: - self._connection.close() - - def is_available(self) -> bool: - if self._connection is None: # pragma: nocover - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._remote_origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: # pragma: nocover - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/venv/lib/python3.10/site-packages/httpcore/_synchronization.py b/venv/lib/python3.10/site-packages/httpcore/_synchronization.py deleted file mode 100644 index 2ecc9e9c363e2f16c4f934cf41cf871826d6a495..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_synchronization.py +++ /dev/null @@ -1,318 +0,0 @@ -from __future__ import annotations - -import threading -import types - -from ._exceptions import ExceptionMapping, PoolTimeout, map_exceptions - -# Our async synchronization primatives use either 'anyio' or 'trio' depending -# on if they're running under asyncio or trio. - -try: - import trio -except (ImportError, NotImplementedError): # pragma: nocover - trio = None # type: ignore - -try: - import anyio -except ImportError: # pragma: nocover - anyio = None # type: ignore - - -def current_async_library() -> str: - # Determine if we're running under trio or asyncio. - # See https://sniffio.readthedocs.io/en/latest/ - try: - import sniffio - except ImportError: # pragma: nocover - environment = "asyncio" - else: - environment = sniffio.current_async_library() - - if environment not in ("asyncio", "trio"): # pragma: nocover - raise RuntimeError("Running under an unsupported async environment.") - - if environment == "asyncio" and anyio is None: # pragma: nocover - raise RuntimeError( - "Running with asyncio requires installation of 'httpcore[asyncio]'." - ) - - if environment == "trio" and trio is None: # pragma: nocover - raise RuntimeError( - "Running with trio requires installation of 'httpcore[trio]'." - ) - - return environment - - -class AsyncLock: - """ - This is a standard lock. - - In the sync case `Lock` provides thread locking. - In the async case `AsyncLock` provides async locking. - """ - - def __init__(self) -> None: - self._backend = "" - - def setup(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a lock with the correct implementation. - """ - self._backend = current_async_library() - if self._backend == "trio": - self._trio_lock = trio.Lock() - elif self._backend == "asyncio": - self._anyio_lock = anyio.Lock() - - async def __aenter__(self) -> AsyncLock: - if not self._backend: - self.setup() - - if self._backend == "trio": - await self._trio_lock.acquire() - elif self._backend == "asyncio": - await self._anyio_lock.acquire() - - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self._backend == "trio": - self._trio_lock.release() - elif self._backend == "asyncio": - self._anyio_lock.release() - - -class AsyncThreadLock: - """ - This is a threading-only lock for no-I/O contexts. - - In the sync case `ThreadLock` provides thread locking. - In the async case `AsyncThreadLock` is a no-op. - """ - - def __enter__(self) -> AsyncThreadLock: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - pass - - -class AsyncEvent: - def __init__(self) -> None: - self._backend = "" - - def setup(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a lock with the correct implementation. - """ - self._backend = current_async_library() - if self._backend == "trio": - self._trio_event = trio.Event() - elif self._backend == "asyncio": - self._anyio_event = anyio.Event() - - def set(self) -> None: - if not self._backend: - self.setup() - - if self._backend == "trio": - self._trio_event.set() - elif self._backend == "asyncio": - self._anyio_event.set() - - async def wait(self, timeout: float | None = None) -> None: - if not self._backend: - self.setup() - - if self._backend == "trio": - trio_exc_map: ExceptionMapping = {trio.TooSlowError: PoolTimeout} - timeout_or_inf = float("inf") if timeout is None else timeout - with map_exceptions(trio_exc_map): - with trio.fail_after(timeout_or_inf): - await self._trio_event.wait() - elif self._backend == "asyncio": - anyio_exc_map: ExceptionMapping = {TimeoutError: PoolTimeout} - with map_exceptions(anyio_exc_map): - with anyio.fail_after(timeout): - await self._anyio_event.wait() - - -class AsyncSemaphore: - def __init__(self, bound: int) -> None: - self._bound = bound - self._backend = "" - - def setup(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a semaphore with the correct implementation. - """ - self._backend = current_async_library() - if self._backend == "trio": - self._trio_semaphore = trio.Semaphore( - initial_value=self._bound, max_value=self._bound - ) - elif self._backend == "asyncio": - self._anyio_semaphore = anyio.Semaphore( - initial_value=self._bound, max_value=self._bound - ) - - async def acquire(self) -> None: - if not self._backend: - self.setup() - - if self._backend == "trio": - await self._trio_semaphore.acquire() - elif self._backend == "asyncio": - await self._anyio_semaphore.acquire() - - async def release(self) -> None: - if self._backend == "trio": - self._trio_semaphore.release() - elif self._backend == "asyncio": - self._anyio_semaphore.release() - - -class AsyncShieldCancellation: - # For certain portions of our codebase where we're dealing with - # closing connections during exception handling we want to shield - # the operation from being cancelled. - # - # with AsyncShieldCancellation(): - # ... # clean-up operations, shielded from cancellation. - - def __init__(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a shielded scope with the correct implementation. - """ - self._backend = current_async_library() - - if self._backend == "trio": - self._trio_shield = trio.CancelScope(shield=True) - elif self._backend == "asyncio": - self._anyio_shield = anyio.CancelScope(shield=True) - - def __enter__(self) -> AsyncShieldCancellation: - if self._backend == "trio": - self._trio_shield.__enter__() - elif self._backend == "asyncio": - self._anyio_shield.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self._backend == "trio": - self._trio_shield.__exit__(exc_type, exc_value, traceback) - elif self._backend == "asyncio": - self._anyio_shield.__exit__(exc_type, exc_value, traceback) - - -# Our thread-based synchronization primitives... - - -class Lock: - """ - This is a standard lock. - - In the sync case `Lock` provides thread locking. - In the async case `AsyncLock` provides async locking. - """ - - def __init__(self) -> None: - self._lock = threading.Lock() - - def __enter__(self) -> Lock: - self._lock.acquire() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self._lock.release() - - -class ThreadLock: - """ - This is a threading-only lock for no-I/O contexts. - - In the sync case `ThreadLock` provides thread locking. - In the async case `AsyncThreadLock` is a no-op. - """ - - def __init__(self) -> None: - self._lock = threading.Lock() - - def __enter__(self) -> ThreadLock: - self._lock.acquire() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self._lock.release() - - -class Event: - def __init__(self) -> None: - self._event = threading.Event() - - def set(self) -> None: - self._event.set() - - def wait(self, timeout: float | None = None) -> None: - if timeout == float("inf"): # pragma: no cover - timeout = None - if not self._event.wait(timeout=timeout): - raise PoolTimeout() # pragma: nocover - - -class Semaphore: - def __init__(self, bound: int) -> None: - self._semaphore = threading.Semaphore(value=bound) - - def acquire(self) -> None: - self._semaphore.acquire() - - def release(self) -> None: - self._semaphore.release() - - -class ShieldCancellation: - # Thread-synchronous codebases don't support cancellation semantics. - # We have this class because we need to mirror the async and sync - # cases within our package, but it's just a no-op. - def __enter__(self) -> ShieldCancellation: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - pass diff --git a/venv/lib/python3.10/site-packages/httpcore/_trace.py b/venv/lib/python3.10/site-packages/httpcore/_trace.py deleted file mode 100644 index 5f1cd7c47829ce17dbcf651ab56b4ffdce04a485..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_trace.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import annotations - -import inspect -import logging -import types -import typing - -from ._models import Request - - -class Trace: - def __init__( - self, - name: str, - logger: logging.Logger, - request: Request | None = None, - kwargs: dict[str, typing.Any] | None = None, - ) -> None: - self.name = name - self.logger = logger - self.trace_extension = ( - None if request is None else request.extensions.get("trace") - ) - self.debug = self.logger.isEnabledFor(logging.DEBUG) - self.kwargs = kwargs or {} - self.return_value: typing.Any = None - self.should_trace = self.debug or self.trace_extension is not None - self.prefix = self.logger.name.split(".")[-1] - - def trace(self, name: str, info: dict[str, typing.Any]) -> None: - if self.trace_extension is not None: - prefix_and_name = f"{self.prefix}.{name}" - ret = self.trace_extension(prefix_and_name, info) - if inspect.iscoroutine(ret): # pragma: no cover - raise TypeError( - "If you are using a synchronous interface, " - "the callback of the `trace` extension should " - "be a normal function instead of an asynchronous function." - ) - - if self.debug: - if not info or "return_value" in info and info["return_value"] is None: - message = name - else: - args = " ".join([f"{key}={value!r}" for key, value in info.items()]) - message = f"{name} {args}" - self.logger.debug(message) - - def __enter__(self) -> Trace: - if self.should_trace: - info = self.kwargs - self.trace(f"{self.name}.started", info) - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self.should_trace: - if exc_value is None: - info = {"return_value": self.return_value} - self.trace(f"{self.name}.complete", info) - else: - info = {"exception": exc_value} - self.trace(f"{self.name}.failed", info) - - async def atrace(self, name: str, info: dict[str, typing.Any]) -> None: - if self.trace_extension is not None: - prefix_and_name = f"{self.prefix}.{name}" - coro = self.trace_extension(prefix_and_name, info) - if not inspect.iscoroutine(coro): # pragma: no cover - raise TypeError( - "If you're using an asynchronous interface, " - "the callback of the `trace` extension should " - "be an asynchronous function rather than a normal function." - ) - await coro - - if self.debug: - if not info or "return_value" in info and info["return_value"] is None: - message = name - else: - args = " ".join([f"{key}={value!r}" for key, value in info.items()]) - message = f"{name} {args}" - self.logger.debug(message) - - async def __aenter__(self) -> Trace: - if self.should_trace: - info = self.kwargs - await self.atrace(f"{self.name}.started", info) - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self.should_trace: - if exc_value is None: - info = {"return_value": self.return_value} - await self.atrace(f"{self.name}.complete", info) - else: - info = {"exception": exc_value} - await self.atrace(f"{self.name}.failed", info) diff --git a/venv/lib/python3.10/site-packages/httpcore/_utils.py b/venv/lib/python3.10/site-packages/httpcore/_utils.py deleted file mode 100644 index c44ff93cb2f572afc6e679308024b744b65c3b0a..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpcore/_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import annotations - -import select -import socket -import sys - - -def is_socket_readable(sock: socket.socket | None) -> bool: - """ - Return whether a socket, as identifed by its file descriptor, is readable. - "A socket is readable" means that the read buffer isn't empty, i.e. that calling - .recv() on it would immediately return some data. - """ - # NOTE: we want check for readability without actually attempting to read, because - # we don't want to block forever if it's not readable. - - # In the case that the socket no longer exists, or cannot return a file - # descriptor, we treat it as being readable, as if it the next read operation - # on it is ready to return the terminating `b""`. - sock_fd = None if sock is None else sock.fileno() - if sock_fd is None or sock_fd < 0: # pragma: nocover - return True - - # The implementation below was stolen from: - # https://github.com/python-trio/trio/blob/20ee2b1b7376db637435d80e266212a35837ddcc/trio/_socket.py#L471-L478 - # See also: https://github.com/encode/httpcore/pull/193#issuecomment-703129316 - - # Use select.select on Windows, and when poll is unavailable and select.poll - # everywhere else. (E.g. When eventlet is in use. See #327) - if ( - sys.platform == "win32" or getattr(select, "poll", None) is None - ): # pragma: nocover - rready, _, _ = select.select([sock_fd], [], [], 0) - return bool(rready) - p = select.poll() - p.register(sock_fd, select.POLLIN) - return bool(p.poll(0)) diff --git a/venv/lib/python3.10/site-packages/httpcore/py.typed b/venv/lib/python3.10/site-packages/httpcore/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/METADATA b/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/METADATA deleted file mode 100644 index b0d2b196385e98259971519793447c1fd7a9a643..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/METADATA +++ /dev/null @@ -1,203 +0,0 @@ -Metadata-Version: 2.3 -Name: httpx -Version: 0.28.1 -Summary: The next generation HTTP client. -Project-URL: Changelog, https://github.com/encode/httpx/blob/master/CHANGELOG.md -Project-URL: Documentation, https://www.python-httpx.org -Project-URL: Homepage, https://github.com/encode/httpx -Project-URL: Source, https://github.com/encode/httpx -Author-email: Tom Christie -License: BSD-3-Clause -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Web Environment -Classifier: Framework :: AsyncIO -Classifier: Framework :: Trio -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.8 -Requires-Dist: anyio -Requires-Dist: certifi -Requires-Dist: httpcore==1.* -Requires-Dist: idna -Provides-Extra: brotli -Requires-Dist: brotli; (platform_python_implementation == 'CPython') and extra == 'brotli' -Requires-Dist: brotlicffi; (platform_python_implementation != 'CPython') and extra == 'brotli' -Provides-Extra: cli -Requires-Dist: click==8.*; extra == 'cli' -Requires-Dist: pygments==2.*; extra == 'cli' -Requires-Dist: rich<14,>=10; extra == 'cli' -Provides-Extra: http2 -Requires-Dist: h2<5,>=3; extra == 'http2' -Provides-Extra: socks -Requires-Dist: socksio==1.*; extra == 'socks' -Provides-Extra: zstd -Requires-Dist: zstandard>=0.18.0; extra == 'zstd' -Description-Content-Type: text/markdown - -

- HTTPX -

- -

HTTPX - A next-generation HTTP client for Python.

- -

- - Test Suite - - - Package version - -

- -HTTPX is a fully featured HTTP client library for Python 3. It includes **an integrated command line client**, has support for both **HTTP/1.1 and HTTP/2**, and provides both **sync and async APIs**. - ---- - -Install HTTPX using pip: - -```shell -$ pip install httpx -``` - -Now, let's get started: - -```pycon ->>> import httpx ->>> r = httpx.get('https://www.example.org/') ->>> r - ->>> r.status_code -200 ->>> r.headers['content-type'] -'text/html; charset=UTF-8' ->>> r.text -'\n\n\nExample Domain...' -``` - -Or, using the command-line client. - -```shell -$ pip install 'httpx[cli]' # The command line client is an optional dependency. -``` - -Which now allows us to use HTTPX directly from the command-line... - -

- httpx --help -

- -Sending a request... - -

- httpx http://httpbin.org/json -

- -## Features - -HTTPX builds on the well-established usability of `requests`, and gives you: - -* A broadly [requests-compatible API](https://www.python-httpx.org/compatibility/). -* An integrated command-line client. -* HTTP/1.1 [and HTTP/2 support](https://www.python-httpx.org/http2/). -* Standard synchronous interface, but with [async support if you need it](https://www.python-httpx.org/async/). -* Ability to make requests directly to [WSGI applications](https://www.python-httpx.org/advanced/transports/#wsgi-transport) or [ASGI applications](https://www.python-httpx.org/advanced/transports/#asgi-transport). -* Strict timeouts everywhere. -* Fully type annotated. -* 100% test coverage. - -Plus all the standard features of `requests`... - -* International Domains and URLs -* Keep-Alive & Connection Pooling -* Sessions with Cookie Persistence -* Browser-style SSL Verification -* Basic/Digest Authentication -* Elegant Key/Value Cookies -* Automatic Decompression -* Automatic Content Decoding -* Unicode Response Bodies -* Multipart File Uploads -* HTTP(S) Proxy Support -* Connection Timeouts -* Streaming Downloads -* .netrc Support -* Chunked Requests - -## Installation - -Install with pip: - -```shell -$ pip install httpx -``` - -Or, to include the optional HTTP/2 support, use: - -```shell -$ pip install httpx[http2] -``` - -HTTPX requires Python 3.8+. - -## Documentation - -Project documentation is available at [https://www.python-httpx.org/](https://www.python-httpx.org/). - -For a run-through of all the basics, head over to the [QuickStart](https://www.python-httpx.org/quickstart/). - -For more advanced topics, see the [Advanced Usage](https://www.python-httpx.org/advanced/) section, the [async support](https://www.python-httpx.org/async/) section, or the [HTTP/2](https://www.python-httpx.org/http2/) section. - -The [Developer Interface](https://www.python-httpx.org/api/) provides a comprehensive API reference. - -To find out about tools that integrate with HTTPX, see [Third Party Packages](https://www.python-httpx.org/third_party_packages/). - -## Contribute - -If you want to contribute with HTTPX check out the [Contributing Guide](https://www.python-httpx.org/contributing/) to learn how to start. - -## Dependencies - -The HTTPX project relies on these excellent libraries: - -* `httpcore` - The underlying transport implementation for `httpx`. - * `h11` - HTTP/1.1 support. -* `certifi` - SSL certificates. -* `idna` - Internationalized domain name support. -* `sniffio` - Async library autodetection. - -As well as these optional installs: - -* `h2` - HTTP/2 support. *(Optional, with `httpx[http2]`)* -* `socksio` - SOCKS proxy support. *(Optional, with `httpx[socks]`)* -* `rich` - Rich terminal support. *(Optional, with `httpx[cli]`)* -* `click` - Command line client support. *(Optional, with `httpx[cli]`)* -* `brotli` or `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional, with `httpx[brotli]`)* -* `zstandard` - Decoding for "zstd" compressed responses. *(Optional, with `httpx[zstd]`)* - -A huge amount of credit is due to `requests` for the API layout that -much of this work follows, as well as to `urllib3` for plenty of design -inspiration around the lower-level networking details. - ---- - -

HTTPX is BSD licensed code.
Designed & crafted with care.

— 🦋 —

- -## Release Information - -### Fixed - -* Reintroduced supposedly-private `URLTypes` shortcut. (#2673) - - ---- - -[Full changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md) diff --git a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/RECORD b/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/RECORD deleted file mode 100644 index a2299ed5e3b59a7b106cae9540e39d6bffc65c82..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/RECORD +++ /dev/null @@ -1,54 +0,0 @@ -../../../bin/httpx,sha256=umGhlm6aL6JBms9rRafCiKdVzD-g-yz1wkVRwJaWvrk,369 -httpx-0.28.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -httpx-0.28.1.dist-info/METADATA,sha256=_rubD48-gNV8gZnDBPNcQzboWB0dGNeYPJJ2a4J5OyU,7052 -httpx-0.28.1.dist-info/RECORD,, -httpx-0.28.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87 -httpx-0.28.1.dist-info/entry_points.txt,sha256=2lVkdQmxLA1pNMgSN2eV89o90HCZezhmNwsy6ryKDSA,37 -httpx-0.28.1.dist-info/licenses/LICENSE.md,sha256=TsWdVE8StfU5o6cW_TIaxYzNgDC0ZSIfLIgCAM3yjY0,1508 -httpx/__init__.py,sha256=CsaZe6yZj0rHg6322AWKWHGTMVr9txgEfD5P3_Rrz60,2171 -httpx/__pycache__/__init__.cpython-310.pyc,, -httpx/__pycache__/__version__.cpython-310.pyc,, -httpx/__pycache__/_api.cpython-310.pyc,, -httpx/__pycache__/_auth.cpython-310.pyc,, -httpx/__pycache__/_client.cpython-310.pyc,, -httpx/__pycache__/_config.cpython-310.pyc,, -httpx/__pycache__/_content.cpython-310.pyc,, -httpx/__pycache__/_decoders.cpython-310.pyc,, -httpx/__pycache__/_exceptions.cpython-310.pyc,, -httpx/__pycache__/_main.cpython-310.pyc,, -httpx/__pycache__/_models.cpython-310.pyc,, -httpx/__pycache__/_multipart.cpython-310.pyc,, -httpx/__pycache__/_status_codes.cpython-310.pyc,, -httpx/__pycache__/_types.cpython-310.pyc,, -httpx/__pycache__/_urlparse.cpython-310.pyc,, -httpx/__pycache__/_urls.cpython-310.pyc,, -httpx/__pycache__/_utils.cpython-310.pyc,, -httpx/__version__.py,sha256=LoUyYeOXTieGzuP_64UL0wxdtxjuu_QbOvE7NOg-IqU,108 -httpx/_api.py,sha256=r_Zgs4jIpcPJLqK5dbbSayqo_iVMKFaxZCd-oOHxLEs,11743 -httpx/_auth.py,sha256=Yr3QwaUSK17rGYx-7j-FdicFIzz4Y9FFV-1F4-7RXX4,11891 -httpx/_client.py,sha256=xD-UG67-WMkeltAAOeGGj-cZ2RRTAm19sWRxlFY7_40,65714 -httpx/_config.py,sha256=pPp2U-wicfcKsF-KYRE1LYdt3e6ERGeIoXZ8Gjo3LWc,8547 -httpx/_content.py,sha256=LGGzrJTR3OvN4Mb1GVVNLXkXJH-6oKlwAttO9p5w_yg,8161 -httpx/_decoders.py,sha256=p0dX8I0NEHexs3UGp4SsZutiMhsXrrWl6-GnqVb0iKM,12041 -httpx/_exceptions.py,sha256=bxW7fxzgVMAdNTbwT0Vnq04gJDW1_gI_GFiQPuMyjL0,8527 -httpx/_main.py,sha256=Cg9GMabiTT_swaDfUgIRitSwxLRMSwUDOm7LdSGqlA4,15626 -httpx/_models.py,sha256=4__Guyv1gLxuZChwim8kfQNiIOcJ9acreFOSurvZfms,44700 -httpx/_multipart.py,sha256=KOHEZZl6oohg9mPaKyyu345qq1rJLg35TUG3YAzXB3Y,9843 -httpx/_status_codes.py,sha256=DYn-2ufBgMeXy5s8x3_TB7wjAuAAMewTakPrm5rXEsc,5639 -httpx/_transports/__init__.py,sha256=GbUoBSAOp7z-l-9j5YhMhR3DMIcn6FVLhj072O3Nnno,275 -httpx/_transports/__pycache__/__init__.cpython-310.pyc,, -httpx/_transports/__pycache__/asgi.cpython-310.pyc,, -httpx/_transports/__pycache__/base.cpython-310.pyc,, -httpx/_transports/__pycache__/default.cpython-310.pyc,, -httpx/_transports/__pycache__/mock.cpython-310.pyc,, -httpx/_transports/__pycache__/wsgi.cpython-310.pyc,, -httpx/_transports/asgi.py,sha256=HRfiDYMPt4wQH2gFgHZg4c-i3sblo6bL5GTqcET-xz8,5501 -httpx/_transports/base.py,sha256=kZS_VMbViYfF570pogUCJ1bulz-ybfL51Pqs9yktebU,2523 -httpx/_transports/default.py,sha256=AzeaRUyVwCccTyyNJexDf0n1dFfzzydpdIQgvw7PLnk,13983 -httpx/_transports/mock.py,sha256=PTo0d567RITXxGrki6kN7_67wwAxfwiMDcuXJiZCjEo,1232 -httpx/_transports/wsgi.py,sha256=NcPX3Xap_EwCFZWO_OaSyQNuInCYx1QMNbO8GAei6jY,4825 -httpx/_types.py,sha256=Jyh41GQq7AOev8IOWKDAg7zCbvHAfufmW5g_PiTtErY,2965 -httpx/_urlparse.py,sha256=ZAmH47ONfkxrrj-PPYhGeiHjb6AjKCS-ANWIN4OL_KY,18546 -httpx/_urls.py,sha256=dX99VR1DSOHpgo9Aq7PzYO4FKdxqKjwyNp8grf8dHN0,21550 -httpx/_utils.py,sha256=_TVeqAKvxJkKHdz7dFeb4s0LZqQXgeFkXSgfiHBK_1o,8285 -httpx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/WHEEL b/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/WHEEL deleted file mode 100644 index 21aaa72961a8af71c17d2cb3b76d5f7f567100e4..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.26.3 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/entry_points.txt b/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/entry_points.txt deleted file mode 100644 index 8ae96007f7d725813fd02dc1d06d3834ee1939e4..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -httpx = httpx:main diff --git a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE.md b/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE.md deleted file mode 100644 index ab79d16a3f4c6c894c028d1f7431811e8711b42b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE.md +++ /dev/null @@ -1,12 +0,0 @@ -Copyright © 2019, [Encode OSS Ltd](https://www.encode.io/). -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.10/site-packages/httpx/__init__.py b/venv/lib/python3.10/site-packages/httpx/__init__.py deleted file mode 100644 index e9addde071f81758baf350c4ab6bde2556340131..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/__init__.py +++ /dev/null @@ -1,105 +0,0 @@ -from .__version__ import __description__, __title__, __version__ -from ._api import * -from ._auth import * -from ._client import * -from ._config import * -from ._content import * -from ._exceptions import * -from ._models import * -from ._status_codes import * -from ._transports import * -from ._types import * -from ._urls import * - -try: - from ._main import main -except ImportError: # pragma: no cover - - def main() -> None: # type: ignore - import sys - - print( - "The httpx command line client could not run because the required " - "dependencies were not installed.\nMake sure you've installed " - "everything with: pip install 'httpx[cli]'" - ) - sys.exit(1) - - -__all__ = [ - "__description__", - "__title__", - "__version__", - "ASGITransport", - "AsyncBaseTransport", - "AsyncByteStream", - "AsyncClient", - "AsyncHTTPTransport", - "Auth", - "BaseTransport", - "BasicAuth", - "ByteStream", - "Client", - "CloseError", - "codes", - "ConnectError", - "ConnectTimeout", - "CookieConflict", - "Cookies", - "create_ssl_context", - "DecodingError", - "delete", - "DigestAuth", - "get", - "head", - "Headers", - "HTTPError", - "HTTPStatusError", - "HTTPTransport", - "InvalidURL", - "Limits", - "LocalProtocolError", - "main", - "MockTransport", - "NetRCAuth", - "NetworkError", - "options", - "patch", - "PoolTimeout", - "post", - "ProtocolError", - "Proxy", - "ProxyError", - "put", - "QueryParams", - "ReadError", - "ReadTimeout", - "RemoteProtocolError", - "request", - "Request", - "RequestError", - "RequestNotRead", - "Response", - "ResponseNotRead", - "stream", - "StreamClosed", - "StreamConsumed", - "StreamError", - "SyncByteStream", - "Timeout", - "TimeoutException", - "TooManyRedirects", - "TransportError", - "UnsupportedProtocol", - "URL", - "USE_CLIENT_DEFAULT", - "WriteError", - "WriteTimeout", - "WSGITransport", -] - - -__locals = locals() -for __name in __all__: - if not __name.startswith("__"): - setattr(__locals[__name], "__module__", "httpx") # noqa diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 67837552176a313faf4e610f66eddd5b2b59aa43..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/__version__.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/__version__.cpython-310.pyc deleted file mode 100644 index 86bb23ae28ced92f8c6c4891b31d6d4083a79e21..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/__version__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_api.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_api.cpython-310.pyc deleted file mode 100644 index f4c52b6fb444094bda579c01a0bcb92972f106c7..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_api.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_auth.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_auth.cpython-310.pyc deleted file mode 100644 index 7ec8e02906c73f1382bda3f4bbc09894a5bdc2ca..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_auth.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_client.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_client.cpython-310.pyc deleted file mode 100644 index 0bf128d2e5203cc0510d317ce00e22ff89010d10..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_client.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_config.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_config.cpython-310.pyc deleted file mode 100644 index 9d2b74330baa40b0c872720be5da8869d1a9f2d0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_config.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_content.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_content.cpython-310.pyc deleted file mode 100644 index cc45bc9d2459a71e41ab107a2cfdc761f2e40b22..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_content.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_decoders.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_decoders.cpython-310.pyc deleted file mode 100644 index 00904d1aec3d85d3d66715ed419cc39cfa91f9a9..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_decoders.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_exceptions.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_exceptions.cpython-310.pyc deleted file mode 100644 index 487ee14117280524cd090a8dcb07ff6abe84ed9a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_exceptions.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_main.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_main.cpython-310.pyc deleted file mode 100644 index 589dd2f31aeec893b9c18dc3f82717ef502cfc8b..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_main.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_models.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_models.cpython-310.pyc deleted file mode 100644 index a385d7c7a48cf981b9220c02a63e6b8bc75551ff..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_models.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_multipart.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_multipart.cpython-310.pyc deleted file mode 100644 index 292a69a13d993544a93f3a6289be8ce328731c3a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_multipart.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_status_codes.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_status_codes.cpython-310.pyc deleted file mode 100644 index 51bd17d70ec780efcddccac01dab4e7336df7489..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_status_codes.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_types.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_types.cpython-310.pyc deleted file mode 100644 index 60daeec437bd62aa7cab827be758d71d65ceb62d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_types.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_urlparse.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_urlparse.cpython-310.pyc deleted file mode 100644 index a2ebc1be8a6f4bc3ec56f7be6630cb852b9a9185..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_urlparse.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_urls.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_urls.cpython-310.pyc deleted file mode 100644 index 4fa01bb68557600bebde924539fb2f9ed1150451..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_urls.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__pycache__/_utils.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/__pycache__/_utils.cpython-310.pyc deleted file mode 100644 index 744d7c92ee816ac937da0e091893425f8ef5524d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/__pycache__/_utils.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/__version__.py b/venv/lib/python3.10/site-packages/httpx/__version__.py deleted file mode 100644 index 801bfacf671017cfbebf1ac26ec385daa02ed260..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/__version__.py +++ /dev/null @@ -1,3 +0,0 @@ -__title__ = "httpx" -__description__ = "A next generation HTTP client, for Python 3." -__version__ = "0.28.1" diff --git a/venv/lib/python3.10/site-packages/httpx/_api.py b/venv/lib/python3.10/site-packages/httpx/_api.py deleted file mode 100644 index c3cda1ecda8629edbdca2e3bc04bc51dba5e1430..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_api.py +++ /dev/null @@ -1,438 +0,0 @@ -from __future__ import annotations - -import typing -from contextlib import contextmanager - -from ._client import Client -from ._config import DEFAULT_TIMEOUT_CONFIG -from ._models import Response -from ._types import ( - AuthTypes, - CookieTypes, - HeaderTypes, - ProxyTypes, - QueryParamTypes, - RequestContent, - RequestData, - RequestFiles, - TimeoutTypes, -) -from ._urls import URL - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - - -__all__ = [ - "delete", - "get", - "head", - "options", - "patch", - "post", - "put", - "request", - "stream", -] - - -def request( - method: str, - url: URL | str, - *, - params: QueryParamTypes | None = None, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - trust_env: bool = True, -) -> Response: - """ - Sends an HTTP request. - - **Parameters:** - - * **method** - HTTP method for the new `Request` object: `GET`, `OPTIONS`, - `HEAD`, `POST`, `PUT`, `PATCH`, or `DELETE`. - * **url** - URL for the new `Request` object. - * **params** - *(optional)* Query parameters to include in the URL, as a - string, dictionary, or sequence of two-tuples. - * **content** - *(optional)* Binary content to include in the body of the - request, as bytes or a byte iterator. - * **data** - *(optional)* Form data to include in the body of the request, - as a dictionary. - * **files** - *(optional)* A dictionary of upload files to include in the - body of the request. - * **json** - *(optional)* A JSON serializable object to include in the body - of the request. - * **headers** - *(optional)* Dictionary of HTTP headers to include in the - request. - * **cookies** - *(optional)* Dictionary of Cookie items to include in the - request. - * **auth** - *(optional)* An authentication class to use when sending the - request. - * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **timeout** - *(optional)* The timeout configuration to use when sending - the request. - * **follow_redirects** - *(optional)* Enables or disables HTTP redirects. - * **verify** - *(optional)* Either `True` to use an SSL context with the - default CA bundle, `False` to disable verification, or an instance of - `ssl.SSLContext` to use a custom context. - * **trust_env** - *(optional)* Enables or disables usage of environment - variables for configuration. - - **Returns:** `Response` - - Usage: - - ``` - >>> import httpx - >>> response = httpx.request('GET', 'https://httpbin.org/get') - >>> response - - ``` - """ - with Client( - cookies=cookies, - proxy=proxy, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) as client: - return client.request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - auth=auth, - follow_redirects=follow_redirects, - ) - - -@contextmanager -def stream( - method: str, - url: URL | str, - *, - params: QueryParamTypes | None = None, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - trust_env: bool = True, -) -> typing.Iterator[Response]: - """ - Alternative to `httpx.request()` that streams the response body - instead of loading it into memory at once. - - **Parameters**: See `httpx.request`. - - See also: [Streaming Responses][0] - - [0]: /quickstart#streaming-responses - """ - with Client( - cookies=cookies, - proxy=proxy, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) as client: - with client.stream( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - auth=auth, - follow_redirects=follow_redirects, - ) as response: - yield response - - -def get( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `GET` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `GET` requests should not include a request body. - """ - return request( - "GET", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def options( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends an `OPTIONS` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `OPTIONS` requests should not include a request body. - """ - return request( - "OPTIONS", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def head( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `HEAD` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `HEAD` requests should not include a request body. - """ - return request( - "HEAD", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def post( - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `POST` request. - - **Parameters**: See `httpx.request`. - """ - return request( - "POST", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def put( - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `PUT` request. - - **Parameters**: See `httpx.request`. - """ - return request( - "PUT", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def patch( - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `PATCH` request. - - **Parameters**: See `httpx.request`. - """ - return request( - "PATCH", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def delete( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - verify: ssl.SSLContext | str | bool = True, - trust_env: bool = True, -) -> Response: - """ - Sends a `DELETE` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `DELETE` requests should not include a request body. - """ - return request( - "DELETE", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) diff --git a/venv/lib/python3.10/site-packages/httpx/_auth.py b/venv/lib/python3.10/site-packages/httpx/_auth.py deleted file mode 100644 index b03971ab4b311d60790dc22ca24d9966426ec0a4..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_auth.py +++ /dev/null @@ -1,348 +0,0 @@ -from __future__ import annotations - -import hashlib -import os -import re -import time -import typing -from base64 import b64encode -from urllib.request import parse_http_list - -from ._exceptions import ProtocolError -from ._models import Cookies, Request, Response -from ._utils import to_bytes, to_str, unquote - -if typing.TYPE_CHECKING: # pragma: no cover - from hashlib import _Hash - - -__all__ = ["Auth", "BasicAuth", "DigestAuth", "NetRCAuth"] - - -class Auth: - """ - Base class for all authentication schemes. - - To implement a custom authentication scheme, subclass `Auth` and override - the `.auth_flow()` method. - - If the authentication scheme does I/O such as disk access or network calls, or uses - synchronization primitives such as locks, you should override `.sync_auth_flow()` - and/or `.async_auth_flow()` instead of `.auth_flow()` to provide specialized - implementations that will be used by `Client` and `AsyncClient` respectively. - """ - - requires_request_body = False - requires_response_body = False - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - """ - Execute the authentication flow. - - To dispatch a request, `yield` it: - - ``` - yield request - ``` - - The client will `.send()` the response back into the flow generator. You can - access it like so: - - ``` - response = yield request - ``` - - A `return` (or reaching the end of the generator) will result in the - client returning the last response obtained from the server. - - You can dispatch as many requests as is necessary. - """ - yield request - - def sync_auth_flow( - self, request: Request - ) -> typing.Generator[Request, Response, None]: - """ - Execute the authentication flow synchronously. - - By default, this defers to `.auth_flow()`. You should override this method - when the authentication scheme does I/O and/or uses concurrency primitives. - """ - if self.requires_request_body: - request.read() - - flow = self.auth_flow(request) - request = next(flow) - - while True: - response = yield request - if self.requires_response_body: - response.read() - - try: - request = flow.send(response) - except StopIteration: - break - - async def async_auth_flow( - self, request: Request - ) -> typing.AsyncGenerator[Request, Response]: - """ - Execute the authentication flow asynchronously. - - By default, this defers to `.auth_flow()`. You should override this method - when the authentication scheme does I/O and/or uses concurrency primitives. - """ - if self.requires_request_body: - await request.aread() - - flow = self.auth_flow(request) - request = next(flow) - - while True: - response = yield request - if self.requires_response_body: - await response.aread() - - try: - request = flow.send(response) - except StopIteration: - break - - -class FunctionAuth(Auth): - """ - Allows the 'auth' argument to be passed as a simple callable function, - that takes the request, and returns a new, modified request. - """ - - def __init__(self, func: typing.Callable[[Request], Request]) -> None: - self._func = func - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - yield self._func(request) - - -class BasicAuth(Auth): - """ - Allows the 'auth' argument to be passed as a (username, password) pair, - and uses HTTP Basic authentication. - """ - - def __init__(self, username: str | bytes, password: str | bytes) -> None: - self._auth_header = self._build_auth_header(username, password) - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - request.headers["Authorization"] = self._auth_header - yield request - - def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str: - userpass = b":".join((to_bytes(username), to_bytes(password))) - token = b64encode(userpass).decode() - return f"Basic {token}" - - -class NetRCAuth(Auth): - """ - Use a 'netrc' file to lookup basic auth credentials based on the url host. - """ - - def __init__(self, file: str | None = None) -> None: - # Lazily import 'netrc'. - # There's no need for us to load this module unless 'NetRCAuth' is being used. - import netrc - - self._netrc_info = netrc.netrc(file) - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - auth_info = self._netrc_info.authenticators(request.url.host) - if auth_info is None or not auth_info[2]: - # The netrc file did not have authentication credentials for this host. - yield request - else: - # Build a basic auth header with credentials from the netrc file. - request.headers["Authorization"] = self._build_auth_header( - username=auth_info[0], password=auth_info[2] - ) - yield request - - def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str: - userpass = b":".join((to_bytes(username), to_bytes(password))) - token = b64encode(userpass).decode() - return f"Basic {token}" - - -class DigestAuth(Auth): - _ALGORITHM_TO_HASH_FUNCTION: dict[str, typing.Callable[[bytes], _Hash]] = { - "MD5": hashlib.md5, - "MD5-SESS": hashlib.md5, - "SHA": hashlib.sha1, - "SHA-SESS": hashlib.sha1, - "SHA-256": hashlib.sha256, - "SHA-256-SESS": hashlib.sha256, - "SHA-512": hashlib.sha512, - "SHA-512-SESS": hashlib.sha512, - } - - def __init__(self, username: str | bytes, password: str | bytes) -> None: - self._username = to_bytes(username) - self._password = to_bytes(password) - self._last_challenge: _DigestAuthChallenge | None = None - self._nonce_count = 1 - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - if self._last_challenge: - request.headers["Authorization"] = self._build_auth_header( - request, self._last_challenge - ) - - response = yield request - - if response.status_code != 401 or "www-authenticate" not in response.headers: - # If the response is not a 401 then we don't - # need to build an authenticated request. - return - - for auth_header in response.headers.get_list("www-authenticate"): - if auth_header.lower().startswith("digest "): - break - else: - # If the response does not include a 'WWW-Authenticate: Digest ...' - # header, then we don't need to build an authenticated request. - return - - self._last_challenge = self._parse_challenge(request, response, auth_header) - self._nonce_count = 1 - - request.headers["Authorization"] = self._build_auth_header( - request, self._last_challenge - ) - if response.cookies: - Cookies(response.cookies).set_cookie_header(request=request) - yield request - - def _parse_challenge( - self, request: Request, response: Response, auth_header: str - ) -> _DigestAuthChallenge: - """ - Returns a challenge from a Digest WWW-Authenticate header. - These take the form of: - `Digest realm="realm@host.com",qop="auth,auth-int",nonce="abc",opaque="xyz"` - """ - scheme, _, fields = auth_header.partition(" ") - - # This method should only ever have been called with a Digest auth header. - assert scheme.lower() == "digest" - - header_dict: dict[str, str] = {} - for field in parse_http_list(fields): - key, value = field.strip().split("=", 1) - header_dict[key] = unquote(value) - - try: - realm = header_dict["realm"].encode() - nonce = header_dict["nonce"].encode() - algorithm = header_dict.get("algorithm", "MD5") - opaque = header_dict["opaque"].encode() if "opaque" in header_dict else None - qop = header_dict["qop"].encode() if "qop" in header_dict else None - return _DigestAuthChallenge( - realm=realm, nonce=nonce, algorithm=algorithm, opaque=opaque, qop=qop - ) - except KeyError as exc: - message = "Malformed Digest WWW-Authenticate header" - raise ProtocolError(message, request=request) from exc - - def _build_auth_header( - self, request: Request, challenge: _DigestAuthChallenge - ) -> str: - hash_func = self._ALGORITHM_TO_HASH_FUNCTION[challenge.algorithm.upper()] - - def digest(data: bytes) -> bytes: - return hash_func(data).hexdigest().encode() - - A1 = b":".join((self._username, challenge.realm, self._password)) - - path = request.url.raw_path - A2 = b":".join((request.method.encode(), path)) - # TODO: implement auth-int - HA2 = digest(A2) - - nc_value = b"%08x" % self._nonce_count - cnonce = self._get_client_nonce(self._nonce_count, challenge.nonce) - self._nonce_count += 1 - - HA1 = digest(A1) - if challenge.algorithm.lower().endswith("-sess"): - HA1 = digest(b":".join((HA1, challenge.nonce, cnonce))) - - qop = self._resolve_qop(challenge.qop, request=request) - if qop is None: - # Following RFC 2069 - digest_data = [HA1, challenge.nonce, HA2] - else: - # Following RFC 2617/7616 - digest_data = [HA1, challenge.nonce, nc_value, cnonce, qop, HA2] - - format_args = { - "username": self._username, - "realm": challenge.realm, - "nonce": challenge.nonce, - "uri": path, - "response": digest(b":".join(digest_data)), - "algorithm": challenge.algorithm.encode(), - } - if challenge.opaque: - format_args["opaque"] = challenge.opaque - if qop: - format_args["qop"] = b"auth" - format_args["nc"] = nc_value - format_args["cnonce"] = cnonce - - return "Digest " + self._get_header_value(format_args) - - def _get_client_nonce(self, nonce_count: int, nonce: bytes) -> bytes: - s = str(nonce_count).encode() - s += nonce - s += time.ctime().encode() - s += os.urandom(8) - - return hashlib.sha1(s).hexdigest()[:16].encode() - - def _get_header_value(self, header_fields: dict[str, bytes]) -> str: - NON_QUOTED_FIELDS = ("algorithm", "qop", "nc") - QUOTED_TEMPLATE = '{}="{}"' - NON_QUOTED_TEMPLATE = "{}={}" - - header_value = "" - for i, (field, value) in enumerate(header_fields.items()): - if i > 0: - header_value += ", " - template = ( - QUOTED_TEMPLATE - if field not in NON_QUOTED_FIELDS - else NON_QUOTED_TEMPLATE - ) - header_value += template.format(field, to_str(value)) - - return header_value - - def _resolve_qop(self, qop: bytes | None, request: Request) -> bytes | None: - if qop is None: - return None - qops = re.split(b", ?", qop) - if b"auth" in qops: - return b"auth" - - if qops == [b"auth-int"]: - raise NotImplementedError("Digest auth-int support is not yet implemented") - - message = f'Unexpected qop value "{qop!r}" in digest auth' - raise ProtocolError(message, request=request) - - -class _DigestAuthChallenge(typing.NamedTuple): - realm: bytes - nonce: bytes - algorithm: str - opaque: bytes | None - qop: bytes | None diff --git a/venv/lib/python3.10/site-packages/httpx/_client.py b/venv/lib/python3.10/site-packages/httpx/_client.py deleted file mode 100644 index 2249231f8c3b912c731ff160344d3672e2f11738..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_client.py +++ /dev/null @@ -1,2019 +0,0 @@ -from __future__ import annotations - -import datetime -import enum -import logging -import time -import typing -import warnings -from contextlib import asynccontextmanager, contextmanager -from types import TracebackType - -from .__version__ import __version__ -from ._auth import Auth, BasicAuth, FunctionAuth -from ._config import ( - DEFAULT_LIMITS, - DEFAULT_MAX_REDIRECTS, - DEFAULT_TIMEOUT_CONFIG, - Limits, - Proxy, - Timeout, -) -from ._decoders import SUPPORTED_DECODERS -from ._exceptions import ( - InvalidURL, - RemoteProtocolError, - TooManyRedirects, - request_context, -) -from ._models import Cookies, Headers, Request, Response -from ._status_codes import codes -from ._transports.base import AsyncBaseTransport, BaseTransport -from ._transports.default import AsyncHTTPTransport, HTTPTransport -from ._types import ( - AsyncByteStream, - AuthTypes, - CertTypes, - CookieTypes, - HeaderTypes, - ProxyTypes, - QueryParamTypes, - RequestContent, - RequestData, - RequestExtensions, - RequestFiles, - SyncByteStream, - TimeoutTypes, -) -from ._urls import URL, QueryParams -from ._utils import URLPattern, get_environment_proxies - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - -__all__ = ["USE_CLIENT_DEFAULT", "AsyncClient", "Client"] - -# The type annotation for @classmethod and context managers here follows PEP 484 -# https://www.python.org/dev/peps/pep-0484/#annotating-instance-and-class-methods -T = typing.TypeVar("T", bound="Client") -U = typing.TypeVar("U", bound="AsyncClient") - - -def _is_https_redirect(url: URL, location: URL) -> bool: - """ - Return 'True' if 'location' is a HTTPS upgrade of 'url' - """ - if url.host != location.host: - return False - - return ( - url.scheme == "http" - and _port_or_default(url) == 80 - and location.scheme == "https" - and _port_or_default(location) == 443 - ) - - -def _port_or_default(url: URL) -> int | None: - if url.port is not None: - return url.port - return {"http": 80, "https": 443}.get(url.scheme) - - -def _same_origin(url: URL, other: URL) -> bool: - """ - Return 'True' if the given URLs share the same origin. - """ - return ( - url.scheme == other.scheme - and url.host == other.host - and _port_or_default(url) == _port_or_default(other) - ) - - -class UseClientDefault: - """ - For some parameters such as `auth=...` and `timeout=...` we need to be able - to indicate the default "unset" state, in a way that is distinctly different - to using `None`. - - The default "unset" state indicates that whatever default is set on the - client should be used. This is different to setting `None`, which - explicitly disables the parameter, possibly overriding a client default. - - For example we use `timeout=USE_CLIENT_DEFAULT` in the `request()` signature. - Omitting the `timeout` parameter will send a request using whatever default - timeout has been configured on the client. Including `timeout=None` will - ensure no timeout is used. - - Note that user code shouldn't need to use the `USE_CLIENT_DEFAULT` constant, - but it is used internally when a parameter is not included. - """ - - -USE_CLIENT_DEFAULT = UseClientDefault() - - -logger = logging.getLogger("httpx") - -USER_AGENT = f"python-httpx/{__version__}" -ACCEPT_ENCODING = ", ".join( - [key for key in SUPPORTED_DECODERS.keys() if key != "identity"] -) - - -class ClientState(enum.Enum): - # UNOPENED: - # The client has been instantiated, but has not been used to send a request, - # or been opened by entering the context of a `with` block. - UNOPENED = 1 - # OPENED: - # The client has either sent a request, or is within a `with` block. - OPENED = 2 - # CLOSED: - # The client has either exited the `with` block, or `close()` has - # been called explicitly. - CLOSED = 3 - - -class BoundSyncStream(SyncByteStream): - """ - A byte stream that is bound to a given response instance, and that - ensures the `response.elapsed` is set once the response is closed. - """ - - def __init__( - self, stream: SyncByteStream, response: Response, start: float - ) -> None: - self._stream = stream - self._response = response - self._start = start - - def __iter__(self) -> typing.Iterator[bytes]: - for chunk in self._stream: - yield chunk - - def close(self) -> None: - elapsed = time.perf_counter() - self._start - self._response.elapsed = datetime.timedelta(seconds=elapsed) - self._stream.close() - - -class BoundAsyncStream(AsyncByteStream): - """ - An async byte stream that is bound to a given response instance, and that - ensures the `response.elapsed` is set once the response is closed. - """ - - def __init__( - self, stream: AsyncByteStream, response: Response, start: float - ) -> None: - self._stream = stream - self._response = response - self._start = start - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - async for chunk in self._stream: - yield chunk - - async def aclose(self) -> None: - elapsed = time.perf_counter() - self._start - self._response.elapsed = datetime.timedelta(seconds=elapsed) - await self._stream.aclose() - - -EventHook = typing.Callable[..., typing.Any] - - -class BaseClient: - def __init__( - self, - *, - auth: AuthTypes | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - max_redirects: int = DEFAULT_MAX_REDIRECTS, - event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, - base_url: URL | str = "", - trust_env: bool = True, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - event_hooks = {} if event_hooks is None else event_hooks - - self._base_url = self._enforce_trailing_slash(URL(base_url)) - - self._auth = self._build_auth(auth) - self._params = QueryParams(params) - self.headers = Headers(headers) - self._cookies = Cookies(cookies) - self._timeout = Timeout(timeout) - self.follow_redirects = follow_redirects - self.max_redirects = max_redirects - self._event_hooks = { - "request": list(event_hooks.get("request", [])), - "response": list(event_hooks.get("response", [])), - } - self._trust_env = trust_env - self._default_encoding = default_encoding - self._state = ClientState.UNOPENED - - @property - def is_closed(self) -> bool: - """ - Check if the client being closed - """ - return self._state == ClientState.CLOSED - - @property - def trust_env(self) -> bool: - return self._trust_env - - def _enforce_trailing_slash(self, url: URL) -> URL: - if url.raw_path.endswith(b"/"): - return url - return url.copy_with(raw_path=url.raw_path + b"/") - - def _get_proxy_map( - self, proxy: ProxyTypes | None, allow_env_proxies: bool - ) -> dict[str, Proxy | None]: - if proxy is None: - if allow_env_proxies: - return { - key: None if url is None else Proxy(url=url) - for key, url in get_environment_proxies().items() - } - return {} - else: - proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy - return {"all://": proxy} - - @property - def timeout(self) -> Timeout: - return self._timeout - - @timeout.setter - def timeout(self, timeout: TimeoutTypes) -> None: - self._timeout = Timeout(timeout) - - @property - def event_hooks(self) -> dict[str, list[EventHook]]: - return self._event_hooks - - @event_hooks.setter - def event_hooks(self, event_hooks: dict[str, list[EventHook]]) -> None: - self._event_hooks = { - "request": list(event_hooks.get("request", [])), - "response": list(event_hooks.get("response", [])), - } - - @property - def auth(self) -> Auth | None: - """ - Authentication class used when none is passed at the request-level. - - See also [Authentication][0]. - - [0]: /quickstart/#authentication - """ - return self._auth - - @auth.setter - def auth(self, auth: AuthTypes) -> None: - self._auth = self._build_auth(auth) - - @property - def base_url(self) -> URL: - """ - Base URL to use when sending requests with relative URLs. - """ - return self._base_url - - @base_url.setter - def base_url(self, url: URL | str) -> None: - self._base_url = self._enforce_trailing_slash(URL(url)) - - @property - def headers(self) -> Headers: - """ - HTTP headers to include when sending requests. - """ - return self._headers - - @headers.setter - def headers(self, headers: HeaderTypes) -> None: - client_headers = Headers( - { - b"Accept": b"*/*", - b"Accept-Encoding": ACCEPT_ENCODING.encode("ascii"), - b"Connection": b"keep-alive", - b"User-Agent": USER_AGENT.encode("ascii"), - } - ) - client_headers.update(headers) - self._headers = client_headers - - @property - def cookies(self) -> Cookies: - """ - Cookie values to include when sending requests. - """ - return self._cookies - - @cookies.setter - def cookies(self, cookies: CookieTypes) -> None: - self._cookies = Cookies(cookies) - - @property - def params(self) -> QueryParams: - """ - Query parameters to include in the URL when sending requests. - """ - return self._params - - @params.setter - def params(self, params: QueryParamTypes) -> None: - self._params = QueryParams(params) - - def build_request( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Request: - """ - Build and return a request instance. - - * The `params`, `headers` and `cookies` arguments - are merged with any values set on the client. - * The `url` argument is merged with any `base_url` set on the client. - - See also: [Request instances][0] - - [0]: /advanced/clients/#request-instances - """ - url = self._merge_url(url) - headers = self._merge_headers(headers) - cookies = self._merge_cookies(cookies) - params = self._merge_queryparams(params) - extensions = {} if extensions is None else extensions - if "timeout" not in extensions: - timeout = ( - self.timeout - if isinstance(timeout, UseClientDefault) - else Timeout(timeout) - ) - extensions = dict(**extensions, timeout=timeout.as_dict()) - return Request( - method, - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - extensions=extensions, - ) - - def _merge_url(self, url: URL | str) -> URL: - """ - Merge a URL argument together with any 'base_url' on the client, - to create the URL used for the outgoing request. - """ - merge_url = URL(url) - if merge_url.is_relative_url: - # To merge URLs we always append to the base URL. To get this - # behaviour correct we always ensure the base URL ends in a '/' - # separator, and strip any leading '/' from the merge URL. - # - # So, eg... - # - # >>> client = Client(base_url="https://www.example.com/subpath") - # >>> client.base_url - # URL('https://www.example.com/subpath/') - # >>> client.build_request("GET", "/path").url - # URL('https://www.example.com/subpath/path') - merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") - return self.base_url.copy_with(raw_path=merge_raw_path) - return merge_url - - def _merge_cookies(self, cookies: CookieTypes | None = None) -> CookieTypes | None: - """ - Merge a cookies argument together with any cookies on the client, - to create the cookies used for the outgoing request. - """ - if cookies or self.cookies: - merged_cookies = Cookies(self.cookies) - merged_cookies.update(cookies) - return merged_cookies - return cookies - - def _merge_headers(self, headers: HeaderTypes | None = None) -> HeaderTypes | None: - """ - Merge a headers argument together with any headers on the client, - to create the headers used for the outgoing request. - """ - merged_headers = Headers(self.headers) - merged_headers.update(headers) - return merged_headers - - def _merge_queryparams( - self, params: QueryParamTypes | None = None - ) -> QueryParamTypes | None: - """ - Merge a queryparams argument together with any queryparams on the client, - to create the queryparams used for the outgoing request. - """ - if params or self.params: - merged_queryparams = QueryParams(self.params) - return merged_queryparams.merge(params) - return params - - def _build_auth(self, auth: AuthTypes | None) -> Auth | None: - if auth is None: - return None - elif isinstance(auth, tuple): - return BasicAuth(username=auth[0], password=auth[1]) - elif isinstance(auth, Auth): - return auth - elif callable(auth): - return FunctionAuth(func=auth) - else: - raise TypeError(f'Invalid "auth" argument: {auth!r}') - - def _build_request_auth( - self, - request: Request, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - ) -> Auth: - auth = ( - self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth) - ) - - if auth is not None: - return auth - - username, password = request.url.username, request.url.password - if username or password: - return BasicAuth(username=username, password=password) - - return Auth() - - def _build_redirect_request(self, request: Request, response: Response) -> Request: - """ - Given a request and a redirect response, return a new request that - should be used to effect the redirect. - """ - method = self._redirect_method(request, response) - url = self._redirect_url(request, response) - headers = self._redirect_headers(request, url, method) - stream = self._redirect_stream(request, method) - cookies = Cookies(self.cookies) - return Request( - method=method, - url=url, - headers=headers, - cookies=cookies, - stream=stream, - extensions=request.extensions, - ) - - def _redirect_method(self, request: Request, response: Response) -> str: - """ - When being redirected we may want to change the method of the request - based on certain specs or browser behavior. - """ - method = request.method - - # https://tools.ietf.org/html/rfc7231#section-6.4.4 - if response.status_code == codes.SEE_OTHER and method != "HEAD": - method = "GET" - - # Do what the browsers do, despite standards... - # Turn 302s into GETs. - if response.status_code == codes.FOUND and method != "HEAD": - method = "GET" - - # If a POST is responded to with a 301, turn it into a GET. - # This bizarre behaviour is explained in 'requests' issue 1704. - if response.status_code == codes.MOVED_PERMANENTLY and method == "POST": - method = "GET" - - return method - - def _redirect_url(self, request: Request, response: Response) -> URL: - """ - Return the URL for the redirect to follow. - """ - location = response.headers["Location"] - - try: - url = URL(location) - except InvalidURL as exc: - raise RemoteProtocolError( - f"Invalid URL in location header: {exc}.", request=request - ) from None - - # Handle malformed 'Location' headers that are "absolute" form, have no host. - # See: https://github.com/encode/httpx/issues/771 - if url.scheme and not url.host: - url = url.copy_with(host=request.url.host) - - # Facilitate relative 'Location' headers, as allowed by RFC 7231. - # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') - if url.is_relative_url: - url = request.url.join(url) - - # Attach previous fragment if needed (RFC 7231 7.1.2) - if request.url.fragment and not url.fragment: - url = url.copy_with(fragment=request.url.fragment) - - return url - - def _redirect_headers(self, request: Request, url: URL, method: str) -> Headers: - """ - Return the headers that should be used for the redirect request. - """ - headers = Headers(request.headers) - - if not _same_origin(url, request.url): - if not _is_https_redirect(request.url, url): - # Strip Authorization headers when responses are redirected - # away from the origin. (Except for direct HTTP to HTTPS redirects.) - headers.pop("Authorization", None) - - # Update the Host header. - headers["Host"] = url.netloc.decode("ascii") - - if method != request.method and method == "GET": - # If we've switch to a 'GET' request, then strip any headers which - # are only relevant to the request body. - headers.pop("Content-Length", None) - headers.pop("Transfer-Encoding", None) - - # We should use the client cookie store to determine any cookie header, - # rather than whatever was on the original outgoing request. - headers.pop("Cookie", None) - - return headers - - def _redirect_stream( - self, request: Request, method: str - ) -> SyncByteStream | AsyncByteStream | None: - """ - Return the body that should be used for the redirect request. - """ - if method != request.method and method == "GET": - return None - - return request.stream - - def _set_timeout(self, request: Request) -> None: - if "timeout" not in request.extensions: - timeout = ( - self.timeout - if isinstance(self.timeout, UseClientDefault) - else Timeout(self.timeout) - ) - request.extensions = dict(**request.extensions, timeout=timeout.as_dict()) - - -class Client(BaseClient): - """ - An HTTP client, with connection pooling, HTTP/2, redirects, cookie persistence, etc. - - It can be shared between threads. - - Usage: - - ```python - >>> client = httpx.Client() - >>> response = client.get('https://example.org') - ``` - - **Parameters:** - - * **auth** - *(optional)* An authentication class to use when sending - requests. - * **params** - *(optional)* Query parameters to include in request URLs, as - a string, dictionary, or sequence of two-tuples. - * **headers** - *(optional)* Dictionary of HTTP headers to include when - sending requests. - * **cookies** - *(optional)* Dictionary of Cookie items to include when - sending requests. - * **verify** - *(optional)* Either `True` to use an SSL context with the - default CA bundle, `False` to disable verification, or an instance of - `ssl.SSLContext` to use a custom context. - * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be - enabled. Defaults to `False`. - * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **timeout** - *(optional)* The timeout configuration to use when sending - requests. - * **limits** - *(optional)* The limits configuration to use. - * **max_redirects** - *(optional)* The maximum number of redirect responses - that should be followed. - * **base_url** - *(optional)* A URL to use as the base when building - request URLs. - * **transport** - *(optional)* A transport class to use for sending requests - over the network. - * **trust_env** - *(optional)* Enables or disables usage of environment - variables for configuration. - * **default_encoding** - *(optional)* The default encoding to use for decoding - response text, if no charset information is included in a response Content-Type - header. Set to a callable for automatic character set detection. Default: "utf-8". - """ - - def __init__( - self, - *, - auth: AuthTypes | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - proxy: ProxyTypes | None = None, - mounts: None | (typing.Mapping[str, BaseTransport | None]) = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - limits: Limits = DEFAULT_LIMITS, - max_redirects: int = DEFAULT_MAX_REDIRECTS, - event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, - base_url: URL | str = "", - transport: BaseTransport | None = None, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - super().__init__( - auth=auth, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - follow_redirects=follow_redirects, - max_redirects=max_redirects, - event_hooks=event_hooks, - base_url=base_url, - trust_env=trust_env, - default_encoding=default_encoding, - ) - - if http2: - try: - import h2 # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using http2=True, but the 'h2' package is not installed. " - "Make sure to install httpx using `pip install httpx[http2]`." - ) from None - - allow_env_proxies = trust_env and transport is None - proxy_map = self._get_proxy_map(proxy, allow_env_proxies) - - self._transport = self._init_transport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - transport=transport, - ) - self._mounts: dict[URLPattern, BaseTransport | None] = { - URLPattern(key): None - if proxy is None - else self._init_proxy_transport( - proxy, - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - for key, proxy in proxy_map.items() - } - if mounts is not None: - self._mounts.update( - {URLPattern(key): transport for key, transport in mounts.items()} - ) - - self._mounts = dict(sorted(self._mounts.items())) - - def _init_transport( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - transport: BaseTransport | None = None, - ) -> BaseTransport: - if transport is not None: - return transport - - return HTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - - def _init_proxy_transport( - self, - proxy: Proxy, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - ) -> BaseTransport: - return HTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - proxy=proxy, - ) - - def _transport_for_url(self, url: URL) -> BaseTransport: - """ - Returns the transport instance that should be used for a given URL. - This will either be the standard connection pool, or a proxy. - """ - for pattern, transport in self._mounts.items(): - if pattern.matches(url): - return self._transport if transport is None else transport - - return self._transport - - def request( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Build and send a request. - - Equivalent to: - - ```python - request = client.build_request(...) - response = client.send(request, ...) - ``` - - See `Client.build_request()`, `Client.send()` and - [Merging of configuration][0] for how the various parameters - are merged with client-level configuration. - - [0]: /advanced/clients/#merging-of-configuration - """ - if cookies is not None: - message = ( - "Setting per-request cookies=<...> is being deprecated, because " - "the expected behaviour on cookie persistence is ambiguous. Set " - "cookies directly on the client instance instead." - ) - warnings.warn(message, DeprecationWarning, stacklevel=2) - - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - return self.send(request, auth=auth, follow_redirects=follow_redirects) - - @contextmanager - def stream( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> typing.Iterator[Response]: - """ - Alternative to `httpx.request()` that streams the response body - instead of loading it into memory at once. - - **Parameters**: See `httpx.request`. - - See also: [Streaming Responses][0] - - [0]: /quickstart#streaming-responses - """ - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - response = self.send( - request=request, - auth=auth, - follow_redirects=follow_redirects, - stream=True, - ) - try: - yield response - finally: - response.close() - - def send( - self, - request: Request, - *, - stream: bool = False, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - ) -> Response: - """ - Send a request. - - The request is sent as-is, unmodified. - - Typically you'll want to build one with `Client.build_request()` - so that any client-level configuration is merged into the request, - but passing an explicit `httpx.Request()` is supported as well. - - See also: [Request instances][0] - - [0]: /advanced/clients/#request-instances - """ - if self._state == ClientState.CLOSED: - raise RuntimeError("Cannot send a request, as the client has been closed.") - - self._state = ClientState.OPENED - follow_redirects = ( - self.follow_redirects - if isinstance(follow_redirects, UseClientDefault) - else follow_redirects - ) - - self._set_timeout(request) - - auth = self._build_request_auth(request, auth) - - response = self._send_handling_auth( - request, - auth=auth, - follow_redirects=follow_redirects, - history=[], - ) - try: - if not stream: - response.read() - - return response - - except BaseException as exc: - response.close() - raise exc - - def _send_handling_auth( - self, - request: Request, - auth: Auth, - follow_redirects: bool, - history: list[Response], - ) -> Response: - auth_flow = auth.sync_auth_flow(request) - try: - request = next(auth_flow) - - while True: - response = self._send_handling_redirects( - request, - follow_redirects=follow_redirects, - history=history, - ) - try: - try: - next_request = auth_flow.send(response) - except StopIteration: - return response - - response.history = list(history) - response.read() - request = next_request - history.append(response) - - except BaseException as exc: - response.close() - raise exc - finally: - auth_flow.close() - - def _send_handling_redirects( - self, - request: Request, - follow_redirects: bool, - history: list[Response], - ) -> Response: - while True: - if len(history) > self.max_redirects: - raise TooManyRedirects( - "Exceeded maximum allowed redirects.", request=request - ) - - for hook in self._event_hooks["request"]: - hook(request) - - response = self._send_single_request(request) - try: - for hook in self._event_hooks["response"]: - hook(response) - response.history = list(history) - - if not response.has_redirect_location: - return response - - request = self._build_redirect_request(request, response) - history = history + [response] - - if follow_redirects: - response.read() - else: - response.next_request = request - return response - - except BaseException as exc: - response.close() - raise exc - - def _send_single_request(self, request: Request) -> Response: - """ - Sends a single request, without handling any redirections. - """ - transport = self._transport_for_url(request.url) - start = time.perf_counter() - - if not isinstance(request.stream, SyncByteStream): - raise RuntimeError( - "Attempted to send an async request with a sync Client instance." - ) - - with request_context(request=request): - response = transport.handle_request(request) - - assert isinstance(response.stream, SyncByteStream) - - response.request = request - response.stream = BoundSyncStream( - response.stream, response=response, start=start - ) - self.cookies.extract_cookies(response) - response.default_encoding = self._default_encoding - - logger.info( - 'HTTP Request: %s %s "%s %d %s"', - request.method, - request.url, - response.http_version, - response.status_code, - response.reason_phrase, - ) - - return response - - def get( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `GET` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "GET", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def options( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send an `OPTIONS` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "OPTIONS", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def head( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `HEAD` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "HEAD", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def post( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `POST` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "POST", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def put( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PUT` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "PUT", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def patch( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PATCH` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "PATCH", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def delete( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `DELETE` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "DELETE", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def close(self) -> None: - """ - Close transport and proxies. - """ - if self._state != ClientState.CLOSED: - self._state = ClientState.CLOSED - - self._transport.close() - for transport in self._mounts.values(): - if transport is not None: - transport.close() - - def __enter__(self: T) -> T: - if self._state != ClientState.UNOPENED: - msg = { - ClientState.OPENED: "Cannot open a client instance more than once.", - ClientState.CLOSED: ( - "Cannot reopen a client instance, once it has been closed." - ), - }[self._state] - raise RuntimeError(msg) - - self._state = ClientState.OPENED - - self._transport.__enter__() - for transport in self._mounts.values(): - if transport is not None: - transport.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - self._state = ClientState.CLOSED - - self._transport.__exit__(exc_type, exc_value, traceback) - for transport in self._mounts.values(): - if transport is not None: - transport.__exit__(exc_type, exc_value, traceback) - - -class AsyncClient(BaseClient): - """ - An asynchronous HTTP client, with connection pooling, HTTP/2, redirects, - cookie persistence, etc. - - It can be shared between tasks. - - Usage: - - ```python - >>> async with httpx.AsyncClient() as client: - >>> response = await client.get('https://example.org') - ``` - - **Parameters:** - - * **auth** - *(optional)* An authentication class to use when sending - requests. - * **params** - *(optional)* Query parameters to include in request URLs, as - a string, dictionary, or sequence of two-tuples. - * **headers** - *(optional)* Dictionary of HTTP headers to include when - sending requests. - * **cookies** - *(optional)* Dictionary of Cookie items to include when - sending requests. - * **verify** - *(optional)* Either `True` to use an SSL context with the - default CA bundle, `False` to disable verification, or an instance of - `ssl.SSLContext` to use a custom context. - * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be - enabled. Defaults to `False`. - * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **timeout** - *(optional)* The timeout configuration to use when sending - requests. - * **limits** - *(optional)* The limits configuration to use. - * **max_redirects** - *(optional)* The maximum number of redirect responses - that should be followed. - * **base_url** - *(optional)* A URL to use as the base when building - request URLs. - * **transport** - *(optional)* A transport class to use for sending requests - over the network. - * **trust_env** - *(optional)* Enables or disables usage of environment - variables for configuration. - * **default_encoding** - *(optional)* The default encoding to use for decoding - response text, if no charset information is included in a response Content-Type - header. Set to a callable for automatic character set detection. Default: "utf-8". - """ - - def __init__( - self, - *, - auth: AuthTypes | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - http1: bool = True, - http2: bool = False, - proxy: ProxyTypes | None = None, - mounts: None | (typing.Mapping[str, AsyncBaseTransport | None]) = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - limits: Limits = DEFAULT_LIMITS, - max_redirects: int = DEFAULT_MAX_REDIRECTS, - event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, - base_url: URL | str = "", - transport: AsyncBaseTransport | None = None, - trust_env: bool = True, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - super().__init__( - auth=auth, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - follow_redirects=follow_redirects, - max_redirects=max_redirects, - event_hooks=event_hooks, - base_url=base_url, - trust_env=trust_env, - default_encoding=default_encoding, - ) - - if http2: - try: - import h2 # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using http2=True, but the 'h2' package is not installed. " - "Make sure to install httpx using `pip install httpx[http2]`." - ) from None - - allow_env_proxies = trust_env and transport is None - proxy_map = self._get_proxy_map(proxy, allow_env_proxies) - - self._transport = self._init_transport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - transport=transport, - ) - - self._mounts: dict[URLPattern, AsyncBaseTransport | None] = { - URLPattern(key): None - if proxy is None - else self._init_proxy_transport( - proxy, - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - for key, proxy in proxy_map.items() - } - if mounts is not None: - self._mounts.update( - {URLPattern(key): transport for key, transport in mounts.items()} - ) - self._mounts = dict(sorted(self._mounts.items())) - - def _init_transport( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - transport: AsyncBaseTransport | None = None, - ) -> AsyncBaseTransport: - if transport is not None: - return transport - - return AsyncHTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - - def _init_proxy_transport( - self, - proxy: Proxy, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - ) -> AsyncBaseTransport: - return AsyncHTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - proxy=proxy, - ) - - def _transport_for_url(self, url: URL) -> AsyncBaseTransport: - """ - Returns the transport instance that should be used for a given URL. - This will either be the standard connection pool, or a proxy. - """ - for pattern, transport in self._mounts.items(): - if pattern.matches(url): - return self._transport if transport is None else transport - - return self._transport - - async def request( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Build and send a request. - - Equivalent to: - - ```python - request = client.build_request(...) - response = await client.send(request, ...) - ``` - - See `AsyncClient.build_request()`, `AsyncClient.send()` - and [Merging of configuration][0] for how the various parameters - are merged with client-level configuration. - - [0]: /advanced/clients/#merging-of-configuration - """ - - if cookies is not None: # pragma: no cover - message = ( - "Setting per-request cookies=<...> is being deprecated, because " - "the expected behaviour on cookie persistence is ambiguous. Set " - "cookies directly on the client instance instead." - ) - warnings.warn(message, DeprecationWarning, stacklevel=2) - - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - return await self.send(request, auth=auth, follow_redirects=follow_redirects) - - @asynccontextmanager - async def stream( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> typing.AsyncIterator[Response]: - """ - Alternative to `httpx.request()` that streams the response body - instead of loading it into memory at once. - - **Parameters**: See `httpx.request`. - - See also: [Streaming Responses][0] - - [0]: /quickstart#streaming-responses - """ - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - response = await self.send( - request=request, - auth=auth, - follow_redirects=follow_redirects, - stream=True, - ) - try: - yield response - finally: - await response.aclose() - - async def send( - self, - request: Request, - *, - stream: bool = False, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - ) -> Response: - """ - Send a request. - - The request is sent as-is, unmodified. - - Typically you'll want to build one with `AsyncClient.build_request()` - so that any client-level configuration is merged into the request, - but passing an explicit `httpx.Request()` is supported as well. - - See also: [Request instances][0] - - [0]: /advanced/clients/#request-instances - """ - if self._state == ClientState.CLOSED: - raise RuntimeError("Cannot send a request, as the client has been closed.") - - self._state = ClientState.OPENED - follow_redirects = ( - self.follow_redirects - if isinstance(follow_redirects, UseClientDefault) - else follow_redirects - ) - - self._set_timeout(request) - - auth = self._build_request_auth(request, auth) - - response = await self._send_handling_auth( - request, - auth=auth, - follow_redirects=follow_redirects, - history=[], - ) - try: - if not stream: - await response.aread() - - return response - - except BaseException as exc: - await response.aclose() - raise exc - - async def _send_handling_auth( - self, - request: Request, - auth: Auth, - follow_redirects: bool, - history: list[Response], - ) -> Response: - auth_flow = auth.async_auth_flow(request) - try: - request = await auth_flow.__anext__() - - while True: - response = await self._send_handling_redirects( - request, - follow_redirects=follow_redirects, - history=history, - ) - try: - try: - next_request = await auth_flow.asend(response) - except StopAsyncIteration: - return response - - response.history = list(history) - await response.aread() - request = next_request - history.append(response) - - except BaseException as exc: - await response.aclose() - raise exc - finally: - await auth_flow.aclose() - - async def _send_handling_redirects( - self, - request: Request, - follow_redirects: bool, - history: list[Response], - ) -> Response: - while True: - if len(history) > self.max_redirects: - raise TooManyRedirects( - "Exceeded maximum allowed redirects.", request=request - ) - - for hook in self._event_hooks["request"]: - await hook(request) - - response = await self._send_single_request(request) - try: - for hook in self._event_hooks["response"]: - await hook(response) - - response.history = list(history) - - if not response.has_redirect_location: - return response - - request = self._build_redirect_request(request, response) - history = history + [response] - - if follow_redirects: - await response.aread() - else: - response.next_request = request - return response - - except BaseException as exc: - await response.aclose() - raise exc - - async def _send_single_request(self, request: Request) -> Response: - """ - Sends a single request, without handling any redirections. - """ - transport = self._transport_for_url(request.url) - start = time.perf_counter() - - if not isinstance(request.stream, AsyncByteStream): - raise RuntimeError( - "Attempted to send an sync request with an AsyncClient instance." - ) - - with request_context(request=request): - response = await transport.handle_async_request(request) - - assert isinstance(response.stream, AsyncByteStream) - response.request = request - response.stream = BoundAsyncStream( - response.stream, response=response, start=start - ) - self.cookies.extract_cookies(response) - response.default_encoding = self._default_encoding - - logger.info( - 'HTTP Request: %s %s "%s %d %s"', - request.method, - request.url, - response.http_version, - response.status_code, - response.reason_phrase, - ) - - return response - - async def get( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `GET` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "GET", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def options( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send an `OPTIONS` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "OPTIONS", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def head( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `HEAD` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "HEAD", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def post( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `POST` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "POST", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def put( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PUT` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "PUT", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def patch( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PATCH` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "PATCH", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def delete( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `DELETE` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "DELETE", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def aclose(self) -> None: - """ - Close transport and proxies. - """ - if self._state != ClientState.CLOSED: - self._state = ClientState.CLOSED - - await self._transport.aclose() - for proxy in self._mounts.values(): - if proxy is not None: - await proxy.aclose() - - async def __aenter__(self: U) -> U: - if self._state != ClientState.UNOPENED: - msg = { - ClientState.OPENED: "Cannot open a client instance more than once.", - ClientState.CLOSED: ( - "Cannot reopen a client instance, once it has been closed." - ), - }[self._state] - raise RuntimeError(msg) - - self._state = ClientState.OPENED - - await self._transport.__aenter__() - for proxy in self._mounts.values(): - if proxy is not None: - await proxy.__aenter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - self._state = ClientState.CLOSED - - await self._transport.__aexit__(exc_type, exc_value, traceback) - for proxy in self._mounts.values(): - if proxy is not None: - await proxy.__aexit__(exc_type, exc_value, traceback) diff --git a/venv/lib/python3.10/site-packages/httpx/_config.py b/venv/lib/python3.10/site-packages/httpx/_config.py deleted file mode 100644 index 467a6c90ae269babe3af7963d9d7c78b9f012268..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_config.py +++ /dev/null @@ -1,248 +0,0 @@ -from __future__ import annotations - -import os -import typing - -from ._models import Headers -from ._types import CertTypes, HeaderTypes, TimeoutTypes -from ._urls import URL - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - -__all__ = ["Limits", "Proxy", "Timeout", "create_ssl_context"] - - -class UnsetType: - pass # pragma: no cover - - -UNSET = UnsetType() - - -def create_ssl_context( - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, -) -> ssl.SSLContext: - import ssl - import warnings - - import certifi - - if verify is True: - if trust_env and os.environ.get("SSL_CERT_FILE"): # pragma: nocover - ctx = ssl.create_default_context(cafile=os.environ["SSL_CERT_FILE"]) - elif trust_env and os.environ.get("SSL_CERT_DIR"): # pragma: nocover - ctx = ssl.create_default_context(capath=os.environ["SSL_CERT_DIR"]) - else: - # Default case... - ctx = ssl.create_default_context(cafile=certifi.where()) - elif verify is False: - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - elif isinstance(verify, str): # pragma: nocover - message = ( - "`verify=` is deprecated. " - "Use `verify=ssl.create_default_context(cafile=...)` " - "or `verify=ssl.create_default_context(capath=...)` instead." - ) - warnings.warn(message, DeprecationWarning) - if os.path.isdir(verify): - return ssl.create_default_context(capath=verify) - return ssl.create_default_context(cafile=verify) - else: - ctx = verify - - if cert: # pragma: nocover - message = ( - "`cert=...` is deprecated. Use `verify=` instead," - "with `.load_cert_chain()` to configure the certificate chain." - ) - warnings.warn(message, DeprecationWarning) - if isinstance(cert, str): - ctx.load_cert_chain(cert) - else: - ctx.load_cert_chain(*cert) - - return ctx - - -class Timeout: - """ - Timeout configuration. - - **Usage**: - - Timeout(None) # No timeouts. - Timeout(5.0) # 5s timeout on all operations. - Timeout(None, connect=5.0) # 5s timeout on connect, no other timeouts. - Timeout(5.0, connect=10.0) # 10s timeout on connect. 5s timeout elsewhere. - Timeout(5.0, pool=None) # No timeout on acquiring connection from pool. - # 5s timeout elsewhere. - """ - - def __init__( - self, - timeout: TimeoutTypes | UnsetType = UNSET, - *, - connect: None | float | UnsetType = UNSET, - read: None | float | UnsetType = UNSET, - write: None | float | UnsetType = UNSET, - pool: None | float | UnsetType = UNSET, - ) -> None: - if isinstance(timeout, Timeout): - # Passed as a single explicit Timeout. - assert connect is UNSET - assert read is UNSET - assert write is UNSET - assert pool is UNSET - self.connect = timeout.connect # type: typing.Optional[float] - self.read = timeout.read # type: typing.Optional[float] - self.write = timeout.write # type: typing.Optional[float] - self.pool = timeout.pool # type: typing.Optional[float] - elif isinstance(timeout, tuple): - # Passed as a tuple. - self.connect = timeout[0] - self.read = timeout[1] - self.write = None if len(timeout) < 3 else timeout[2] - self.pool = None if len(timeout) < 4 else timeout[3] - elif not ( - isinstance(connect, UnsetType) - or isinstance(read, UnsetType) - or isinstance(write, UnsetType) - or isinstance(pool, UnsetType) - ): - self.connect = connect - self.read = read - self.write = write - self.pool = pool - else: - if isinstance(timeout, UnsetType): - raise ValueError( - "httpx.Timeout must either include a default, or set all " - "four parameters explicitly." - ) - self.connect = timeout if isinstance(connect, UnsetType) else connect - self.read = timeout if isinstance(read, UnsetType) else read - self.write = timeout if isinstance(write, UnsetType) else write - self.pool = timeout if isinstance(pool, UnsetType) else pool - - def as_dict(self) -> dict[str, float | None]: - return { - "connect": self.connect, - "read": self.read, - "write": self.write, - "pool": self.pool, - } - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, self.__class__) - and self.connect == other.connect - and self.read == other.read - and self.write == other.write - and self.pool == other.pool - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - if len({self.connect, self.read, self.write, self.pool}) == 1: - return f"{class_name}(timeout={self.connect})" - return ( - f"{class_name}(connect={self.connect}, " - f"read={self.read}, write={self.write}, pool={self.pool})" - ) - - -class Limits: - """ - Configuration for limits to various client behaviors. - - **Parameters:** - - * **max_connections** - The maximum number of concurrent connections that may be - established. - * **max_keepalive_connections** - Allow the connection pool to maintain - keep-alive connections below this point. Should be less than or equal - to `max_connections`. - * **keepalive_expiry** - Time limit on idle keep-alive connections in seconds. - """ - - def __init__( - self, - *, - max_connections: int | None = None, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = 5.0, - ) -> None: - self.max_connections = max_connections - self.max_keepalive_connections = max_keepalive_connections - self.keepalive_expiry = keepalive_expiry - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, self.__class__) - and self.max_connections == other.max_connections - and self.max_keepalive_connections == other.max_keepalive_connections - and self.keepalive_expiry == other.keepalive_expiry - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - return ( - f"{class_name}(max_connections={self.max_connections}, " - f"max_keepalive_connections={self.max_keepalive_connections}, " - f"keepalive_expiry={self.keepalive_expiry})" - ) - - -class Proxy: - def __init__( - self, - url: URL | str, - *, - ssl_context: ssl.SSLContext | None = None, - auth: tuple[str, str] | None = None, - headers: HeaderTypes | None = None, - ) -> None: - url = URL(url) - headers = Headers(headers) - - if url.scheme not in ("http", "https", "socks5", "socks5h"): - raise ValueError(f"Unknown scheme for proxy URL {url!r}") - - if url.username or url.password: - # Remove any auth credentials from the URL. - auth = (url.username, url.password) - url = url.copy_with(username=None, password=None) - - self.url = url - self.auth = auth - self.headers = headers - self.ssl_context = ssl_context - - @property - def raw_auth(self) -> tuple[bytes, bytes] | None: - # The proxy authentication as raw bytes. - return ( - None - if self.auth is None - else (self.auth[0].encode("utf-8"), self.auth[1].encode("utf-8")) - ) - - def __repr__(self) -> str: - # The authentication is represented with the password component masked. - auth = (self.auth[0], "********") if self.auth else None - - # Build a nice concise representation. - url_str = f"{str(self.url)!r}" - auth_str = f", auth={auth!r}" if auth else "" - headers_str = f", headers={dict(self.headers)!r}" if self.headers else "" - return f"Proxy({url_str}{auth_str}{headers_str})" - - -DEFAULT_TIMEOUT_CONFIG = Timeout(timeout=5.0) -DEFAULT_LIMITS = Limits(max_connections=100, max_keepalive_connections=20) -DEFAULT_MAX_REDIRECTS = 20 diff --git a/venv/lib/python3.10/site-packages/httpx/_content.py b/venv/lib/python3.10/site-packages/httpx/_content.py deleted file mode 100644 index 6f479a0885f723b7395843d41164a87041820776..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_content.py +++ /dev/null @@ -1,240 +0,0 @@ -from __future__ import annotations - -import inspect -import warnings -from json import dumps as json_dumps -from typing import ( - Any, - AsyncIterable, - AsyncIterator, - Iterable, - Iterator, - Mapping, -) -from urllib.parse import urlencode - -from ._exceptions import StreamClosed, StreamConsumed -from ._multipart import MultipartStream -from ._types import ( - AsyncByteStream, - RequestContent, - RequestData, - RequestFiles, - ResponseContent, - SyncByteStream, -) -from ._utils import peek_filelike_length, primitive_value_to_str - -__all__ = ["ByteStream"] - - -class ByteStream(AsyncByteStream, SyncByteStream): - def __init__(self, stream: bytes) -> None: - self._stream = stream - - def __iter__(self) -> Iterator[bytes]: - yield self._stream - - async def __aiter__(self) -> AsyncIterator[bytes]: - yield self._stream - - -class IteratorByteStream(SyncByteStream): - CHUNK_SIZE = 65_536 - - def __init__(self, stream: Iterable[bytes]) -> None: - self._stream = stream - self._is_stream_consumed = False - self._is_generator = inspect.isgenerator(stream) - - def __iter__(self) -> Iterator[bytes]: - if self._is_stream_consumed and self._is_generator: - raise StreamConsumed() - - self._is_stream_consumed = True - if hasattr(self._stream, "read"): - # File-like interfaces should use 'read' directly. - chunk = self._stream.read(self.CHUNK_SIZE) - while chunk: - yield chunk - chunk = self._stream.read(self.CHUNK_SIZE) - else: - # Otherwise iterate. - for part in self._stream: - yield part - - -class AsyncIteratorByteStream(AsyncByteStream): - CHUNK_SIZE = 65_536 - - def __init__(self, stream: AsyncIterable[bytes]) -> None: - self._stream = stream - self._is_stream_consumed = False - self._is_generator = inspect.isasyncgen(stream) - - async def __aiter__(self) -> AsyncIterator[bytes]: - if self._is_stream_consumed and self._is_generator: - raise StreamConsumed() - - self._is_stream_consumed = True - if hasattr(self._stream, "aread"): - # File-like interfaces should use 'aread' directly. - chunk = await self._stream.aread(self.CHUNK_SIZE) - while chunk: - yield chunk - chunk = await self._stream.aread(self.CHUNK_SIZE) - else: - # Otherwise iterate. - async for part in self._stream: - yield part - - -class UnattachedStream(AsyncByteStream, SyncByteStream): - """ - If a request or response is serialized using pickle, then it is no longer - attached to a stream for I/O purposes. Any stream operations should result - in `httpx.StreamClosed`. - """ - - def __iter__(self) -> Iterator[bytes]: - raise StreamClosed() - - async def __aiter__(self) -> AsyncIterator[bytes]: - raise StreamClosed() - yield b"" # pragma: no cover - - -def encode_content( - content: str | bytes | Iterable[bytes] | AsyncIterable[bytes], -) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: - if isinstance(content, (bytes, str)): - body = content.encode("utf-8") if isinstance(content, str) else content - content_length = len(body) - headers = {"Content-Length": str(content_length)} if body else {} - return headers, ByteStream(body) - - elif isinstance(content, Iterable) and not isinstance(content, dict): - # `not isinstance(content, dict)` is a bit oddly specific, but it - # catches a case that's easy for users to make in error, and would - # otherwise pass through here, like any other bytes-iterable, - # because `dict` happens to be iterable. See issue #2491. - content_length_or_none = peek_filelike_length(content) - - if content_length_or_none is None: - headers = {"Transfer-Encoding": "chunked"} - else: - headers = {"Content-Length": str(content_length_or_none)} - return headers, IteratorByteStream(content) # type: ignore - - elif isinstance(content, AsyncIterable): - headers = {"Transfer-Encoding": "chunked"} - return headers, AsyncIteratorByteStream(content) - - raise TypeError(f"Unexpected type for 'content', {type(content)!r}") - - -def encode_urlencoded_data( - data: RequestData, -) -> tuple[dict[str, str], ByteStream]: - plain_data = [] - for key, value in data.items(): - if isinstance(value, (list, tuple)): - plain_data.extend([(key, primitive_value_to_str(item)) for item in value]) - else: - plain_data.append((key, primitive_value_to_str(value))) - body = urlencode(plain_data, doseq=True).encode("utf-8") - content_length = str(len(body)) - content_type = "application/x-www-form-urlencoded" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_multipart_data( - data: RequestData, files: RequestFiles, boundary: bytes | None -) -> tuple[dict[str, str], MultipartStream]: - multipart = MultipartStream(data=data, files=files, boundary=boundary) - headers = multipart.get_headers() - return headers, multipart - - -def encode_text(text: str) -> tuple[dict[str, str], ByteStream]: - body = text.encode("utf-8") - content_length = str(len(body)) - content_type = "text/plain; charset=utf-8" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_html(html: str) -> tuple[dict[str, str], ByteStream]: - body = html.encode("utf-8") - content_length = str(len(body)) - content_type = "text/html; charset=utf-8" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_json(json: Any) -> tuple[dict[str, str], ByteStream]: - body = json_dumps( - json, ensure_ascii=False, separators=(",", ":"), allow_nan=False - ).encode("utf-8") - content_length = str(len(body)) - content_type = "application/json" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_request( - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: Any | None = None, - boundary: bytes | None = None, -) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: - """ - Handles encoding the given `content`, `data`, `files`, and `json`, - returning a two-tuple of (, ). - """ - if data is not None and not isinstance(data, Mapping): - # We prefer to separate `content=` - # for raw request content, and `data=
` for url encoded or - # multipart form content. - # - # However for compat with requests, we *do* still support - # `data=` usages. We deal with that case here, treating it - # as if `content=<...>` had been supplied instead. - message = "Use 'content=<...>' to upload raw bytes/text content." - warnings.warn(message, DeprecationWarning, stacklevel=2) - return encode_content(data) - - if content is not None: - return encode_content(content) - elif files: - return encode_multipart_data(data or {}, files, boundary) - elif data: - return encode_urlencoded_data(data) - elif json is not None: - return encode_json(json) - - return {}, ByteStream(b"") - - -def encode_response( - content: ResponseContent | None = None, - text: str | None = None, - html: str | None = None, - json: Any | None = None, -) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: - """ - Handles encoding the given `content`, returning a two-tuple of - (, ). - """ - if content is not None: - return encode_content(content) - elif text is not None: - return encode_text(text) - elif html is not None: - return encode_html(html) - elif json is not None: - return encode_json(json) - - return {}, ByteStream(b"") diff --git a/venv/lib/python3.10/site-packages/httpx/_decoders.py b/venv/lib/python3.10/site-packages/httpx/_decoders.py deleted file mode 100644 index 899dfada878e1181fca6d3c75a79526a076abb9e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_decoders.py +++ /dev/null @@ -1,393 +0,0 @@ -""" -Handlers for Content-Encoding. - -See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding -""" - -from __future__ import annotations - -import codecs -import io -import typing -import zlib - -from ._exceptions import DecodingError - -# Brotli support is optional -try: - # The C bindings in `brotli` are recommended for CPython. - import brotli -except ImportError: # pragma: no cover - try: - # The CFFI bindings in `brotlicffi` are recommended for PyPy - # and other environments. - import brotlicffi as brotli - except ImportError: - brotli = None - - -# Zstandard support is optional -try: - import zstandard -except ImportError: # pragma: no cover - zstandard = None # type: ignore - - -class ContentDecoder: - def decode(self, data: bytes) -> bytes: - raise NotImplementedError() # pragma: no cover - - def flush(self) -> bytes: - raise NotImplementedError() # pragma: no cover - - -class IdentityDecoder(ContentDecoder): - """ - Handle unencoded data. - """ - - def decode(self, data: bytes) -> bytes: - return data - - def flush(self) -> bytes: - return b"" - - -class DeflateDecoder(ContentDecoder): - """ - Handle 'deflate' decoding. - - See: https://stackoverflow.com/questions/1838699 - """ - - def __init__(self) -> None: - self.first_attempt = True - self.decompressor = zlib.decompressobj() - - def decode(self, data: bytes) -> bytes: - was_first_attempt = self.first_attempt - self.first_attempt = False - try: - return self.decompressor.decompress(data) - except zlib.error as exc: - if was_first_attempt: - self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS) - return self.decode(data) - raise DecodingError(str(exc)) from exc - - def flush(self) -> bytes: - try: - return self.decompressor.flush() - except zlib.error as exc: # pragma: no cover - raise DecodingError(str(exc)) from exc - - -class GZipDecoder(ContentDecoder): - """ - Handle 'gzip' decoding. - - See: https://stackoverflow.com/questions/1838699 - """ - - def __init__(self) -> None: - self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16) - - def decode(self, data: bytes) -> bytes: - try: - return self.decompressor.decompress(data) - except zlib.error as exc: - raise DecodingError(str(exc)) from exc - - def flush(self) -> bytes: - try: - return self.decompressor.flush() - except zlib.error as exc: # pragma: no cover - raise DecodingError(str(exc)) from exc - - -class BrotliDecoder(ContentDecoder): - """ - Handle 'brotli' decoding. - - Requires `pip install brotlipy`. See: https://brotlipy.readthedocs.io/ - or `pip install brotli`. See https://github.com/google/brotli - Supports both 'brotlipy' and 'Brotli' packages since they share an import - name. The top branches are for 'brotlipy' and bottom branches for 'Brotli' - """ - - def __init__(self) -> None: - if brotli is None: # pragma: no cover - raise ImportError( - "Using 'BrotliDecoder', but neither of the 'brotlicffi' or 'brotli' " - "packages have been installed. " - "Make sure to install httpx using `pip install httpx[brotli]`." - ) from None - - self.decompressor = brotli.Decompressor() - self.seen_data = False - self._decompress: typing.Callable[[bytes], bytes] - if hasattr(self.decompressor, "decompress"): - # The 'brotlicffi' package. - self._decompress = self.decompressor.decompress # pragma: no cover - else: - # The 'brotli' package. - self._decompress = self.decompressor.process # pragma: no cover - - def decode(self, data: bytes) -> bytes: - if not data: - return b"" - self.seen_data = True - try: - return self._decompress(data) - except brotli.error as exc: - raise DecodingError(str(exc)) from exc - - def flush(self) -> bytes: - if not self.seen_data: - return b"" - try: - if hasattr(self.decompressor, "finish"): - # Only available in the 'brotlicffi' package. - - # As the decompressor decompresses eagerly, this - # will never actually emit any data. However, it will potentially throw - # errors if a truncated or damaged data stream has been used. - self.decompressor.finish() # pragma: no cover - return b"" - except brotli.error as exc: # pragma: no cover - raise DecodingError(str(exc)) from exc - - -class ZStandardDecoder(ContentDecoder): - """ - Handle 'zstd' RFC 8878 decoding. - - Requires `pip install zstandard`. - Can be installed as a dependency of httpx using `pip install httpx[zstd]`. - """ - - # inspired by the ZstdDecoder implementation in urllib3 - def __init__(self) -> None: - if zstandard is None: # pragma: no cover - raise ImportError( - "Using 'ZStandardDecoder', ..." - "Make sure to install httpx using `pip install httpx[zstd]`." - ) from None - - self.decompressor = zstandard.ZstdDecompressor().decompressobj() - self.seen_data = False - - def decode(self, data: bytes) -> bytes: - assert zstandard is not None - self.seen_data = True - output = io.BytesIO() - try: - output.write(self.decompressor.decompress(data)) - while self.decompressor.eof and self.decompressor.unused_data: - unused_data = self.decompressor.unused_data - self.decompressor = zstandard.ZstdDecompressor().decompressobj() - output.write(self.decompressor.decompress(unused_data)) - except zstandard.ZstdError as exc: - raise DecodingError(str(exc)) from exc - return output.getvalue() - - def flush(self) -> bytes: - if not self.seen_data: - return b"" - ret = self.decompressor.flush() # note: this is a no-op - if not self.decompressor.eof: - raise DecodingError("Zstandard data is incomplete") # pragma: no cover - return bytes(ret) - - -class MultiDecoder(ContentDecoder): - """ - Handle the case where multiple encodings have been applied. - """ - - def __init__(self, children: typing.Sequence[ContentDecoder]) -> None: - """ - 'children' should be a sequence of decoders in the order in which - each was applied. - """ - # Note that we reverse the order for decoding. - self.children = list(reversed(children)) - - def decode(self, data: bytes) -> bytes: - for child in self.children: - data = child.decode(data) - return data - - def flush(self) -> bytes: - data = b"" - for child in self.children: - data = child.decode(data) + child.flush() - return data - - -class ByteChunker: - """ - Handles returning byte content in fixed-size chunks. - """ - - def __init__(self, chunk_size: int | None = None) -> None: - self._buffer = io.BytesIO() - self._chunk_size = chunk_size - - def decode(self, content: bytes) -> list[bytes]: - if self._chunk_size is None: - return [content] if content else [] - - self._buffer.write(content) - if self._buffer.tell() >= self._chunk_size: - value = self._buffer.getvalue() - chunks = [ - value[i : i + self._chunk_size] - for i in range(0, len(value), self._chunk_size) - ] - if len(chunks[-1]) == self._chunk_size: - self._buffer.seek(0) - self._buffer.truncate() - return chunks - else: - self._buffer.seek(0) - self._buffer.write(chunks[-1]) - self._buffer.truncate() - return chunks[:-1] - else: - return [] - - def flush(self) -> list[bytes]: - value = self._buffer.getvalue() - self._buffer.seek(0) - self._buffer.truncate() - return [value] if value else [] - - -class TextChunker: - """ - Handles returning text content in fixed-size chunks. - """ - - def __init__(self, chunk_size: int | None = None) -> None: - self._buffer = io.StringIO() - self._chunk_size = chunk_size - - def decode(self, content: str) -> list[str]: - if self._chunk_size is None: - return [content] if content else [] - - self._buffer.write(content) - if self._buffer.tell() >= self._chunk_size: - value = self._buffer.getvalue() - chunks = [ - value[i : i + self._chunk_size] - for i in range(0, len(value), self._chunk_size) - ] - if len(chunks[-1]) == self._chunk_size: - self._buffer.seek(0) - self._buffer.truncate() - return chunks - else: - self._buffer.seek(0) - self._buffer.write(chunks[-1]) - self._buffer.truncate() - return chunks[:-1] - else: - return [] - - def flush(self) -> list[str]: - value = self._buffer.getvalue() - self._buffer.seek(0) - self._buffer.truncate() - return [value] if value else [] - - -class TextDecoder: - """ - Handles incrementally decoding bytes into text - """ - - def __init__(self, encoding: str = "utf-8") -> None: - self.decoder = codecs.getincrementaldecoder(encoding)(errors="replace") - - def decode(self, data: bytes) -> str: - return self.decoder.decode(data) - - def flush(self) -> str: - return self.decoder.decode(b"", True) - - -class LineDecoder: - """ - Handles incrementally reading lines from text. - - Has the same behaviour as the stdllib splitlines, - but handling the input iteratively. - """ - - def __init__(self) -> None: - self.buffer: list[str] = [] - self.trailing_cr: bool = False - - def decode(self, text: str) -> list[str]: - # See https://docs.python.org/3/library/stdtypes.html#str.splitlines - NEWLINE_CHARS = "\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029" - - # We always push a trailing `\r` into the next decode iteration. - if self.trailing_cr: - text = "\r" + text - self.trailing_cr = False - if text.endswith("\r"): - self.trailing_cr = True - text = text[:-1] - - if not text: - # NOTE: the edge case input of empty text doesn't occur in practice, - # because other httpx internals filter out this value - return [] # pragma: no cover - - trailing_newline = text[-1] in NEWLINE_CHARS - lines = text.splitlines() - - if len(lines) == 1 and not trailing_newline: - # No new lines, buffer the input and continue. - self.buffer.append(lines[0]) - return [] - - if self.buffer: - # Include any existing buffer in the first portion of the - # splitlines result. - lines = ["".join(self.buffer) + lines[0]] + lines[1:] - self.buffer = [] - - if not trailing_newline: - # If the last segment of splitlines is not newline terminated, - # then drop it from our output and start a new buffer. - self.buffer = [lines.pop()] - - return lines - - def flush(self) -> list[str]: - if not self.buffer and not self.trailing_cr: - return [] - - lines = ["".join(self.buffer)] - self.buffer = [] - self.trailing_cr = False - return lines - - -SUPPORTED_DECODERS = { - "identity": IdentityDecoder, - "gzip": GZipDecoder, - "deflate": DeflateDecoder, - "br": BrotliDecoder, - "zstd": ZStandardDecoder, -} - - -if brotli is None: - SUPPORTED_DECODERS.pop("br") # pragma: no cover -if zstandard is None: - SUPPORTED_DECODERS.pop("zstd") # pragma: no cover diff --git a/venv/lib/python3.10/site-packages/httpx/_exceptions.py b/venv/lib/python3.10/site-packages/httpx/_exceptions.py deleted file mode 100644 index 77f45a6d3986d15626fc8a5fd459d6a3e0fbe466..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_exceptions.py +++ /dev/null @@ -1,379 +0,0 @@ -""" -Our exception hierarchy: - -* HTTPError - x RequestError - + TransportError - - TimeoutException - · ConnectTimeout - · ReadTimeout - · WriteTimeout - · PoolTimeout - - NetworkError - · ConnectError - · ReadError - · WriteError - · CloseError - - ProtocolError - · LocalProtocolError - · RemoteProtocolError - - ProxyError - - UnsupportedProtocol - + DecodingError - + TooManyRedirects - x HTTPStatusError -* InvalidURL -* CookieConflict -* StreamError - x StreamConsumed - x StreamClosed - x ResponseNotRead - x RequestNotRead -""" - -from __future__ import annotations - -import contextlib -import typing - -if typing.TYPE_CHECKING: - from ._models import Request, Response # pragma: no cover - -__all__ = [ - "CloseError", - "ConnectError", - "ConnectTimeout", - "CookieConflict", - "DecodingError", - "HTTPError", - "HTTPStatusError", - "InvalidURL", - "LocalProtocolError", - "NetworkError", - "PoolTimeout", - "ProtocolError", - "ProxyError", - "ReadError", - "ReadTimeout", - "RemoteProtocolError", - "RequestError", - "RequestNotRead", - "ResponseNotRead", - "StreamClosed", - "StreamConsumed", - "StreamError", - "TimeoutException", - "TooManyRedirects", - "TransportError", - "UnsupportedProtocol", - "WriteError", - "WriteTimeout", -] - - -class HTTPError(Exception): - """ - Base class for `RequestError` and `HTTPStatusError`. - - Useful for `try...except` blocks when issuing a request, - and then calling `.raise_for_status()`. - - For example: - - ``` - try: - response = httpx.get("https://www.example.com") - response.raise_for_status() - except httpx.HTTPError as exc: - print(f"HTTP Exception for {exc.request.url} - {exc}") - ``` - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - self._request: Request | None = None - - @property - def request(self) -> Request: - if self._request is None: - raise RuntimeError("The .request property has not been set.") - return self._request - - @request.setter - def request(self, request: Request) -> None: - self._request = request - - -class RequestError(HTTPError): - """ - Base class for all exceptions that may occur when issuing a `.request()`. - """ - - def __init__(self, message: str, *, request: Request | None = None) -> None: - super().__init__(message) - # At the point an exception is raised we won't typically have a request - # instance to associate it with. - # - # The 'request_context' context manager is used within the Client and - # Response methods in order to ensure that any raised exceptions - # have a `.request` property set on them. - self._request = request - - -class TransportError(RequestError): - """ - Base class for all exceptions that occur at the level of the Transport API. - """ - - -# Timeout exceptions... - - -class TimeoutException(TransportError): - """ - The base class for timeout errors. - - An operation has timed out. - """ - - -class ConnectTimeout(TimeoutException): - """ - Timed out while connecting to the host. - """ - - -class ReadTimeout(TimeoutException): - """ - Timed out while receiving data from the host. - """ - - -class WriteTimeout(TimeoutException): - """ - Timed out while sending data to the host. - """ - - -class PoolTimeout(TimeoutException): - """ - Timed out waiting to acquire a connection from the pool. - """ - - -# Core networking exceptions... - - -class NetworkError(TransportError): - """ - The base class for network-related errors. - - An error occurred while interacting with the network. - """ - - -class ReadError(NetworkError): - """ - Failed to receive data from the network. - """ - - -class WriteError(NetworkError): - """ - Failed to send data through the network. - """ - - -class ConnectError(NetworkError): - """ - Failed to establish a connection. - """ - - -class CloseError(NetworkError): - """ - Failed to close a connection. - """ - - -# Other transport exceptions... - - -class ProxyError(TransportError): - """ - An error occurred while establishing a proxy connection. - """ - - -class UnsupportedProtocol(TransportError): - """ - Attempted to make a request to an unsupported protocol. - - For example issuing a request to `ftp://www.example.com`. - """ - - -class ProtocolError(TransportError): - """ - The protocol was violated. - """ - - -class LocalProtocolError(ProtocolError): - """ - A protocol was violated by the client. - - For example if the user instantiated a `Request` instance explicitly, - failed to include the mandatory `Host:` header, and then issued it directly - using `client.send()`. - """ - - -class RemoteProtocolError(ProtocolError): - """ - The protocol was violated by the server. - - For example, returning malformed HTTP. - """ - - -# Other request exceptions... - - -class DecodingError(RequestError): - """ - Decoding of the response failed, due to a malformed encoding. - """ - - -class TooManyRedirects(RequestError): - """ - Too many redirects. - """ - - -# Client errors - - -class HTTPStatusError(HTTPError): - """ - The response had an error HTTP status of 4xx or 5xx. - - May be raised when calling `response.raise_for_status()` - """ - - def __init__(self, message: str, *, request: Request, response: Response) -> None: - super().__init__(message) - self.request = request - self.response = response - - -class InvalidURL(Exception): - """ - URL is improperly formed or cannot be parsed. - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - - -class CookieConflict(Exception): - """ - Attempted to lookup a cookie by name, but multiple cookies existed. - - Can occur when calling `response.cookies.get(...)`. - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - - -# Stream exceptions... - -# These may occur as the result of a programming error, by accessing -# the request/response stream in an invalid manner. - - -class StreamError(RuntimeError): - """ - The base class for stream exceptions. - - The developer made an error in accessing the request stream in - an invalid way. - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - - -class StreamConsumed(StreamError): - """ - Attempted to read or stream content, but the content has already - been streamed. - """ - - def __init__(self) -> None: - message = ( - "Attempted to read or stream some content, but the content has " - "already been streamed. For requests, this could be due to passing " - "a generator as request content, and then receiving a redirect " - "response or a secondary request as part of an authentication flow." - "For responses, this could be due to attempting to stream the response " - "content more than once." - ) - super().__init__(message) - - -class StreamClosed(StreamError): - """ - Attempted to read or stream response content, but the request has been - closed. - """ - - def __init__(self) -> None: - message = ( - "Attempted to read or stream content, but the stream has " "been closed." - ) - super().__init__(message) - - -class ResponseNotRead(StreamError): - """ - Attempted to access streaming response content, without having called `read()`. - """ - - def __init__(self) -> None: - message = ( - "Attempted to access streaming response content," - " without having called `read()`." - ) - super().__init__(message) - - -class RequestNotRead(StreamError): - """ - Attempted to access streaming request content, without having called `read()`. - """ - - def __init__(self) -> None: - message = ( - "Attempted to access streaming request content," - " without having called `read()`." - ) - super().__init__(message) - - -@contextlib.contextmanager -def request_context( - request: Request | None = None, -) -> typing.Iterator[None]: - """ - A context manager that can be used to attach the given request context - to any `RequestError` exceptions that are raised within the block. - """ - try: - yield - except RequestError as exc: - if request is not None: - exc.request = request - raise exc diff --git a/venv/lib/python3.10/site-packages/httpx/_main.py b/venv/lib/python3.10/site-packages/httpx/_main.py deleted file mode 100644 index cffa4bb7db0f930f4db56653a061c4d7400ba4e6..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_main.py +++ /dev/null @@ -1,506 +0,0 @@ -from __future__ import annotations - -import functools -import json -import sys -import typing - -import click -import pygments.lexers -import pygments.util -import rich.console -import rich.markup -import rich.progress -import rich.syntax -import rich.table - -from ._client import Client -from ._exceptions import RequestError -from ._models import Response -from ._status_codes import codes - -if typing.TYPE_CHECKING: - import httpcore # pragma: no cover - - -def print_help() -> None: - console = rich.console.Console() - - console.print("[bold]HTTPX :butterfly:", justify="center") - console.print() - console.print("A next generation HTTP client.", justify="center") - console.print() - console.print( - "Usage: [bold]httpx[/bold] [cyan] [OPTIONS][/cyan] ", justify="left" - ) - console.print() - - table = rich.table.Table.grid(padding=1, pad_edge=True) - table.add_column("Parameter", no_wrap=True, justify="left", style="bold") - table.add_column("Description") - table.add_row( - "-m, --method [cyan]METHOD", - "Request method, such as GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD.\n" - "[Default: GET, or POST if a request body is included]", - ) - table.add_row( - "-p, --params [cyan] ...", - "Query parameters to include in the request URL.", - ) - table.add_row( - "-c, --content [cyan]TEXT", "Byte content to include in the request body." - ) - table.add_row( - "-d, --data [cyan] ...", "Form data to include in the request body." - ) - table.add_row( - "-f, --files [cyan] ...", - "Form files to include in the request body.", - ) - table.add_row("-j, --json [cyan]TEXT", "JSON data to include in the request body.") - table.add_row( - "-h, --headers [cyan] ...", - "Include additional HTTP headers in the request.", - ) - table.add_row( - "--cookies [cyan] ...", "Cookies to include in the request." - ) - table.add_row( - "--auth [cyan]", - "Username and password to include in the request. Specify '-' for the password" - " to use a password prompt. Note that using --verbose/-v will expose" - " the Authorization header, including the password encoding" - " in a trivially reversible format.", - ) - - table.add_row( - "--proxy [cyan]URL", - "Send the request via a proxy. Should be the URL giving the proxy address.", - ) - - table.add_row( - "--timeout [cyan]FLOAT", - "Timeout value to use for network operations, such as establishing the" - " connection, reading some data, etc... [Default: 5.0]", - ) - - table.add_row("--follow-redirects", "Automatically follow redirects.") - table.add_row("--no-verify", "Disable SSL verification.") - table.add_row( - "--http2", "Send the request using HTTP/2, if the remote server supports it." - ) - - table.add_row( - "--download [cyan]FILE", - "Save the response content as a file, rather than displaying it.", - ) - - table.add_row("-v, --verbose", "Verbose output. Show request as well as response.") - table.add_row("--help", "Show this message and exit.") - console.print(table) - - -def get_lexer_for_response(response: Response) -> str: - content_type = response.headers.get("Content-Type") - if content_type is not None: - mime_type, _, _ = content_type.partition(";") - try: - return typing.cast( - str, pygments.lexers.get_lexer_for_mimetype(mime_type.strip()).name - ) - except pygments.util.ClassNotFound: # pragma: no cover - pass - return "" # pragma: no cover - - -def format_request_headers(request: httpcore.Request, http2: bool = False) -> str: - version = "HTTP/2" if http2 else "HTTP/1.1" - headers = [ - (name.lower() if http2 else name, value) for name, value in request.headers - ] - method = request.method.decode("ascii") - target = request.url.target.decode("ascii") - lines = [f"{method} {target} {version}"] + [ - f"{name.decode('ascii')}: {value.decode('ascii')}" for name, value in headers - ] - return "\n".join(lines) - - -def format_response_headers( - http_version: bytes, - status: int, - reason_phrase: bytes | None, - headers: list[tuple[bytes, bytes]], -) -> str: - version = http_version.decode("ascii") - reason = ( - codes.get_reason_phrase(status) - if reason_phrase is None - else reason_phrase.decode("ascii") - ) - lines = [f"{version} {status} {reason}"] + [ - f"{name.decode('ascii')}: {value.decode('ascii')}" for name, value in headers - ] - return "\n".join(lines) - - -def print_request_headers(request: httpcore.Request, http2: bool = False) -> None: - console = rich.console.Console() - http_text = format_request_headers(request, http2=http2) - syntax = rich.syntax.Syntax(http_text, "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - syntax = rich.syntax.Syntax("", "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - - -def print_response_headers( - http_version: bytes, - status: int, - reason_phrase: bytes | None, - headers: list[tuple[bytes, bytes]], -) -> None: - console = rich.console.Console() - http_text = format_response_headers(http_version, status, reason_phrase, headers) - syntax = rich.syntax.Syntax(http_text, "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - syntax = rich.syntax.Syntax("", "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - - -def print_response(response: Response) -> None: - console = rich.console.Console() - lexer_name = get_lexer_for_response(response) - if lexer_name: - if lexer_name.lower() == "json": - try: - data = response.json() - text = json.dumps(data, indent=4) - except ValueError: # pragma: no cover - text = response.text - else: - text = response.text - - syntax = rich.syntax.Syntax(text, lexer_name, theme="ansi_dark", word_wrap=True) - console.print(syntax) - else: - console.print(f"<{len(response.content)} bytes of binary data>") - - -_PCTRTT = typing.Tuple[typing.Tuple[str, str], ...] -_PCTRTTT = typing.Tuple[_PCTRTT, ...] -_PeerCertRetDictType = typing.Dict[str, typing.Union[str, _PCTRTTT, _PCTRTT]] - - -def format_certificate(cert: _PeerCertRetDictType) -> str: # pragma: no cover - lines = [] - for key, value in cert.items(): - if isinstance(value, (list, tuple)): - lines.append(f"* {key}:") - for item in value: - if key in ("subject", "issuer"): - for sub_item in item: - lines.append(f"* {sub_item[0]}: {sub_item[1]!r}") - elif isinstance(item, tuple) and len(item) == 2: - lines.append(f"* {item[0]}: {item[1]!r}") - else: - lines.append(f"* {item!r}") - else: - lines.append(f"* {key}: {value!r}") - return "\n".join(lines) - - -def trace( - name: str, info: typing.Mapping[str, typing.Any], verbose: bool = False -) -> None: - console = rich.console.Console() - if name == "connection.connect_tcp.started" and verbose: - host = info["host"] - console.print(f"* Connecting to {host!r}") - elif name == "connection.connect_tcp.complete" and verbose: - stream = info["return_value"] - server_addr = stream.get_extra_info("server_addr") - console.print(f"* Connected to {server_addr[0]!r} on port {server_addr[1]}") - elif name == "connection.start_tls.complete" and verbose: # pragma: no cover - stream = info["return_value"] - ssl_object = stream.get_extra_info("ssl_object") - version = ssl_object.version() - cipher = ssl_object.cipher() - server_cert = ssl_object.getpeercert() - alpn = ssl_object.selected_alpn_protocol() - console.print(f"* SSL established using {version!r} / {cipher[0]!r}") - console.print(f"* Selected ALPN protocol: {alpn!r}") - if server_cert: - console.print("* Server certificate:") - console.print(format_certificate(server_cert)) - elif name == "http11.send_request_headers.started" and verbose: - request = info["request"] - print_request_headers(request, http2=False) - elif name == "http2.send_request_headers.started" and verbose: # pragma: no cover - request = info["request"] - print_request_headers(request, http2=True) - elif name == "http11.receive_response_headers.complete": - http_version, status, reason_phrase, headers = info["return_value"] - print_response_headers(http_version, status, reason_phrase, headers) - elif name == "http2.receive_response_headers.complete": # pragma: no cover - status, headers = info["return_value"] - http_version = b"HTTP/2" - reason_phrase = None - print_response_headers(http_version, status, reason_phrase, headers) - - -def download_response(response: Response, download: typing.BinaryIO) -> None: - console = rich.console.Console() - console.print() - content_length = response.headers.get("Content-Length") - with rich.progress.Progress( - "[progress.description]{task.description}", - "[progress.percentage]{task.percentage:>3.0f}%", - rich.progress.BarColumn(bar_width=None), - rich.progress.DownloadColumn(), - rich.progress.TransferSpeedColumn(), - ) as progress: - description = f"Downloading [bold]{rich.markup.escape(download.name)}" - download_task = progress.add_task( - description, - total=int(content_length or 0), - start=content_length is not None, - ) - for chunk in response.iter_bytes(): - download.write(chunk) - progress.update(download_task, completed=response.num_bytes_downloaded) - - -def validate_json( - ctx: click.Context, - param: click.Option | click.Parameter, - value: typing.Any, -) -> typing.Any: - if value is None: - return None - - try: - return json.loads(value) - except json.JSONDecodeError: # pragma: no cover - raise click.BadParameter("Not valid JSON") - - -def validate_auth( - ctx: click.Context, - param: click.Option | click.Parameter, - value: typing.Any, -) -> typing.Any: - if value == (None, None): - return None - - username, password = value - if password == "-": # pragma: no cover - password = click.prompt("Password", hide_input=True) - return (username, password) - - -def handle_help( - ctx: click.Context, - param: click.Option | click.Parameter, - value: typing.Any, -) -> None: - if not value or ctx.resilient_parsing: - return - - print_help() - ctx.exit() - - -@click.command(add_help_option=False) -@click.argument("url", type=str) -@click.option( - "--method", - "-m", - "method", - type=str, - help=( - "Request method, such as GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD. " - "[Default: GET, or POST if a request body is included]" - ), -) -@click.option( - "--params", - "-p", - "params", - type=(str, str), - multiple=True, - help="Query parameters to include in the request URL.", -) -@click.option( - "--content", - "-c", - "content", - type=str, - help="Byte content to include in the request body.", -) -@click.option( - "--data", - "-d", - "data", - type=(str, str), - multiple=True, - help="Form data to include in the request body.", -) -@click.option( - "--files", - "-f", - "files", - type=(str, click.File(mode="rb")), - multiple=True, - help="Form files to include in the request body.", -) -@click.option( - "--json", - "-j", - "json", - type=str, - callback=validate_json, - help="JSON data to include in the request body.", -) -@click.option( - "--headers", - "-h", - "headers", - type=(str, str), - multiple=True, - help="Include additional HTTP headers in the request.", -) -@click.option( - "--cookies", - "cookies", - type=(str, str), - multiple=True, - help="Cookies to include in the request.", -) -@click.option( - "--auth", - "auth", - type=(str, str), - default=(None, None), - callback=validate_auth, - help=( - "Username and password to include in the request. " - "Specify '-' for the password to use a password prompt. " - "Note that using --verbose/-v will expose the Authorization header, " - "including the password encoding in a trivially reversible format." - ), -) -@click.option( - "--proxy", - "proxy", - type=str, - default=None, - help="Send the request via a proxy. Should be the URL giving the proxy address.", -) -@click.option( - "--timeout", - "timeout", - type=float, - default=5.0, - help=( - "Timeout value to use for network operations, such as establishing the " - "connection, reading some data, etc... [Default: 5.0]" - ), -) -@click.option( - "--follow-redirects", - "follow_redirects", - is_flag=True, - default=False, - help="Automatically follow redirects.", -) -@click.option( - "--no-verify", - "verify", - is_flag=True, - default=True, - help="Disable SSL verification.", -) -@click.option( - "--http2", - "http2", - type=bool, - is_flag=True, - default=False, - help="Send the request using HTTP/2, if the remote server supports it.", -) -@click.option( - "--download", - type=click.File("wb"), - help="Save the response content as a file, rather than displaying it.", -) -@click.option( - "--verbose", - "-v", - type=bool, - is_flag=True, - default=False, - help="Verbose. Show request as well as response.", -) -@click.option( - "--help", - is_flag=True, - is_eager=True, - expose_value=False, - callback=handle_help, - help="Show this message and exit.", -) -def main( - url: str, - method: str, - params: list[tuple[str, str]], - content: str, - data: list[tuple[str, str]], - files: list[tuple[str, click.File]], - json: str, - headers: list[tuple[str, str]], - cookies: list[tuple[str, str]], - auth: tuple[str, str] | None, - proxy: str, - timeout: float, - follow_redirects: bool, - verify: bool, - http2: bool, - download: typing.BinaryIO | None, - verbose: bool, -) -> None: - """ - An HTTP command line client. - Sends a request and displays the response. - """ - if not method: - method = "POST" if content or data or files or json else "GET" - - try: - with Client(proxy=proxy, timeout=timeout, http2=http2, verify=verify) as client: - with client.stream( - method, - url, - params=list(params), - content=content, - data=dict(data), - files=files, # type: ignore - json=json, - headers=headers, - cookies=dict(cookies), - auth=auth, - follow_redirects=follow_redirects, - extensions={"trace": functools.partial(trace, verbose=verbose)}, - ) as response: - if download is not None: - download_response(response, download) - else: - response.read() - if response.content: - print_response(response) - - except RequestError as exc: - console = rich.console.Console() - console.print(f"[red]{type(exc).__name__}[/red]: {exc}") - sys.exit(1) - - sys.exit(0 if response.is_success else 1) diff --git a/venv/lib/python3.10/site-packages/httpx/_models.py b/venv/lib/python3.10/site-packages/httpx/_models.py deleted file mode 100644 index 67d74bf86bfc80e22d9a4a3153572845accd9039..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_models.py +++ /dev/null @@ -1,1277 +0,0 @@ -from __future__ import annotations - -import codecs -import datetime -import email.message -import json as jsonlib -import re -import typing -import urllib.request -from collections.abc import Mapping -from http.cookiejar import Cookie, CookieJar - -from ._content import ByteStream, UnattachedStream, encode_request, encode_response -from ._decoders import ( - SUPPORTED_DECODERS, - ByteChunker, - ContentDecoder, - IdentityDecoder, - LineDecoder, - MultiDecoder, - TextChunker, - TextDecoder, -) -from ._exceptions import ( - CookieConflict, - HTTPStatusError, - RequestNotRead, - ResponseNotRead, - StreamClosed, - StreamConsumed, - request_context, -) -from ._multipart import get_multipart_boundary_from_content_type -from ._status_codes import codes -from ._types import ( - AsyncByteStream, - CookieTypes, - HeaderTypes, - QueryParamTypes, - RequestContent, - RequestData, - RequestExtensions, - RequestFiles, - ResponseContent, - ResponseExtensions, - SyncByteStream, -) -from ._urls import URL -from ._utils import to_bytes_or_str, to_str - -__all__ = ["Cookies", "Headers", "Request", "Response"] - -SENSITIVE_HEADERS = {"authorization", "proxy-authorization"} - - -def _is_known_encoding(encoding: str) -> bool: - """ - Return `True` if `encoding` is a known codec. - """ - try: - codecs.lookup(encoding) - except LookupError: - return False - return True - - -def _normalize_header_key(key: str | bytes, encoding: str | None = None) -> bytes: - """ - Coerce str/bytes into a strictly byte-wise HTTP header key. - """ - return key if isinstance(key, bytes) else key.encode(encoding or "ascii") - - -def _normalize_header_value(value: str | bytes, encoding: str | None = None) -> bytes: - """ - Coerce str/bytes into a strictly byte-wise HTTP header value. - """ - if isinstance(value, bytes): - return value - if not isinstance(value, str): - raise TypeError(f"Header value must be str or bytes, not {type(value)}") - return value.encode(encoding or "ascii") - - -def _parse_content_type_charset(content_type: str) -> str | None: - # We used to use `cgi.parse_header()` here, but `cgi` became a dead battery. - # See: https://peps.python.org/pep-0594/#cgi - msg = email.message.Message() - msg["content-type"] = content_type - return msg.get_content_charset(failobj=None) - - -def _parse_header_links(value: str) -> list[dict[str, str]]: - """ - Returns a list of parsed link headers, for more info see: - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link - The generic syntax of those is: - Link: < uri-reference >; param1=value1; param2="value2" - So for instance: - Link; '; type="image/jpeg",;' - would return - [ - {"url": "http:/.../front.jpeg", "type": "image/jpeg"}, - {"url": "http://.../back.jpeg"}, - ] - :param value: HTTP Link entity-header field - :return: list of parsed link headers - """ - links: list[dict[str, str]] = [] - replace_chars = " '\"" - value = value.strip(replace_chars) - if not value: - return links - for val in re.split(", *<", value): - try: - url, params = val.split(";", 1) - except ValueError: - url, params = val, "" - link = {"url": url.strip("<> '\"")} - for param in params.split(";"): - try: - key, value = param.split("=") - except ValueError: - break - link[key.strip(replace_chars)] = value.strip(replace_chars) - links.append(link) - return links - - -def _obfuscate_sensitive_headers( - items: typing.Iterable[tuple[typing.AnyStr, typing.AnyStr]], -) -> typing.Iterator[tuple[typing.AnyStr, typing.AnyStr]]: - for k, v in items: - if to_str(k.lower()) in SENSITIVE_HEADERS: - v = to_bytes_or_str("[secure]", match_type_of=v) - yield k, v - - -class Headers(typing.MutableMapping[str, str]): - """ - HTTP headers, as a case-insensitive multi-dict. - """ - - def __init__( - self, - headers: HeaderTypes | None = None, - encoding: str | None = None, - ) -> None: - self._list = [] # type: typing.List[typing.Tuple[bytes, bytes, bytes]] - - if isinstance(headers, Headers): - self._list = list(headers._list) - elif isinstance(headers, Mapping): - for k, v in headers.items(): - bytes_key = _normalize_header_key(k, encoding) - bytes_value = _normalize_header_value(v, encoding) - self._list.append((bytes_key, bytes_key.lower(), bytes_value)) - elif headers is not None: - for k, v in headers: - bytes_key = _normalize_header_key(k, encoding) - bytes_value = _normalize_header_value(v, encoding) - self._list.append((bytes_key, bytes_key.lower(), bytes_value)) - - self._encoding = encoding - - @property - def encoding(self) -> str: - """ - Header encoding is mandated as ascii, but we allow fallbacks to utf-8 - or iso-8859-1. - """ - if self._encoding is None: - for encoding in ["ascii", "utf-8"]: - for key, value in self.raw: - try: - key.decode(encoding) - value.decode(encoding) - except UnicodeDecodeError: - break - else: - # The else block runs if 'break' did not occur, meaning - # all values fitted the encoding. - self._encoding = encoding - break - else: - # The ISO-8859-1 encoding covers all 256 code points in a byte, - # so will never raise decode errors. - self._encoding = "iso-8859-1" - return self._encoding - - @encoding.setter - def encoding(self, value: str) -> None: - self._encoding = value - - @property - def raw(self) -> list[tuple[bytes, bytes]]: - """ - Returns a list of the raw header items, as byte pairs. - """ - return [(raw_key, value) for raw_key, _, value in self._list] - - def keys(self) -> typing.KeysView[str]: - return {key.decode(self.encoding): None for _, key, value in self._list}.keys() - - def values(self) -> typing.ValuesView[str]: - values_dict: dict[str, str] = {} - for _, key, value in self._list: - str_key = key.decode(self.encoding) - str_value = value.decode(self.encoding) - if str_key in values_dict: - values_dict[str_key] += f", {str_value}" - else: - values_dict[str_key] = str_value - return values_dict.values() - - def items(self) -> typing.ItemsView[str, str]: - """ - Return `(key, value)` items of headers. Concatenate headers - into a single comma separated value when a key occurs multiple times. - """ - values_dict: dict[str, str] = {} - for _, key, value in self._list: - str_key = key.decode(self.encoding) - str_value = value.decode(self.encoding) - if str_key in values_dict: - values_dict[str_key] += f", {str_value}" - else: - values_dict[str_key] = str_value - return values_dict.items() - - def multi_items(self) -> list[tuple[str, str]]: - """ - Return a list of `(key, value)` pairs of headers. Allow multiple - occurrences of the same key without concatenating into a single - comma separated value. - """ - return [ - (key.decode(self.encoding), value.decode(self.encoding)) - for _, key, value in self._list - ] - - def get(self, key: str, default: typing.Any = None) -> typing.Any: - """ - Return a header value. If multiple occurrences of the header occur - then concatenate them together with commas. - """ - try: - return self[key] - except KeyError: - return default - - def get_list(self, key: str, split_commas: bool = False) -> list[str]: - """ - Return a list of all header values for a given key. - If `split_commas=True` is passed, then any comma separated header - values are split into multiple return strings. - """ - get_header_key = key.lower().encode(self.encoding) - - values = [ - item_value.decode(self.encoding) - for _, item_key, item_value in self._list - if item_key.lower() == get_header_key - ] - - if not split_commas: - return values - - split_values = [] - for value in values: - split_values.extend([item.strip() for item in value.split(",")]) - return split_values - - def update(self, headers: HeaderTypes | None = None) -> None: # type: ignore - headers = Headers(headers) - for key in headers.keys(): - if key in self: - self.pop(key) - self._list.extend(headers._list) - - def copy(self) -> Headers: - return Headers(self, encoding=self.encoding) - - def __getitem__(self, key: str) -> str: - """ - Return a single header value. - - If there are multiple headers with the same key, then we concatenate - them with commas. See: https://tools.ietf.org/html/rfc7230#section-3.2.2 - """ - normalized_key = key.lower().encode(self.encoding) - - items = [ - header_value.decode(self.encoding) - for _, header_key, header_value in self._list - if header_key == normalized_key - ] - - if items: - return ", ".join(items) - - raise KeyError(key) - - def __setitem__(self, key: str, value: str) -> None: - """ - Set the header `key` to `value`, removing any duplicate entries. - Retains insertion order. - """ - set_key = key.encode(self._encoding or "utf-8") - set_value = value.encode(self._encoding or "utf-8") - lookup_key = set_key.lower() - - found_indexes = [ - idx - for idx, (_, item_key, _) in enumerate(self._list) - if item_key == lookup_key - ] - - for idx in reversed(found_indexes[1:]): - del self._list[idx] - - if found_indexes: - idx = found_indexes[0] - self._list[idx] = (set_key, lookup_key, set_value) - else: - self._list.append((set_key, lookup_key, set_value)) - - def __delitem__(self, key: str) -> None: - """ - Remove the header `key`. - """ - del_key = key.lower().encode(self.encoding) - - pop_indexes = [ - idx - for idx, (_, item_key, _) in enumerate(self._list) - if item_key.lower() == del_key - ] - - if not pop_indexes: - raise KeyError(key) - - for idx in reversed(pop_indexes): - del self._list[idx] - - def __contains__(self, key: typing.Any) -> bool: - header_key = key.lower().encode(self.encoding) - return header_key in [key for _, key, _ in self._list] - - def __iter__(self) -> typing.Iterator[typing.Any]: - return iter(self.keys()) - - def __len__(self) -> int: - return len(self._list) - - def __eq__(self, other: typing.Any) -> bool: - try: - other_headers = Headers(other) - except ValueError: - return False - - self_list = [(key, value) for _, key, value in self._list] - other_list = [(key, value) for _, key, value in other_headers._list] - return sorted(self_list) == sorted(other_list) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - - encoding_str = "" - if self.encoding != "ascii": - encoding_str = f", encoding={self.encoding!r}" - - as_list = list(_obfuscate_sensitive_headers(self.multi_items())) - as_dict = dict(as_list) - - no_duplicate_keys = len(as_dict) == len(as_list) - if no_duplicate_keys: - return f"{class_name}({as_dict!r}{encoding_str})" - return f"{class_name}({as_list!r}{encoding_str})" - - -class Request: - def __init__( - self, - method: str, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - stream: SyncByteStream | AsyncByteStream | None = None, - extensions: RequestExtensions | None = None, - ) -> None: - self.method = method.upper() - self.url = URL(url) if params is None else URL(url, params=params) - self.headers = Headers(headers) - self.extensions = {} if extensions is None else dict(extensions) - - if cookies: - Cookies(cookies).set_cookie_header(self) - - if stream is None: - content_type: str | None = self.headers.get("content-type") - headers, stream = encode_request( - content=content, - data=data, - files=files, - json=json, - boundary=get_multipart_boundary_from_content_type( - content_type=content_type.encode(self.headers.encoding) - if content_type - else None - ), - ) - self._prepare(headers) - self.stream = stream - # Load the request body, except for streaming content. - if isinstance(stream, ByteStream): - self.read() - else: - # There's an important distinction between `Request(content=...)`, - # and `Request(stream=...)`. - # - # Using `content=...` implies automatically populated `Host` and content - # headers, of either `Content-Length: ...` or `Transfer-Encoding: chunked`. - # - # Using `stream=...` will not automatically include *any* - # auto-populated headers. - # - # As an end-user you don't really need `stream=...`. It's only - # useful when: - # - # * Preserving the request stream when copying requests, eg for redirects. - # * Creating request instances on the *server-side* of the transport API. - self.stream = stream - - def _prepare(self, default_headers: dict[str, str]) -> None: - for key, value in default_headers.items(): - # Ignore Transfer-Encoding if the Content-Length has been set explicitly. - if key.lower() == "transfer-encoding" and "Content-Length" in self.headers: - continue - self.headers.setdefault(key, value) - - auto_headers: list[tuple[bytes, bytes]] = [] - - has_host = "Host" in self.headers - has_content_length = ( - "Content-Length" in self.headers or "Transfer-Encoding" in self.headers - ) - - if not has_host and self.url.host: - auto_headers.append((b"Host", self.url.netloc)) - if not has_content_length and self.method in ("POST", "PUT", "PATCH"): - auto_headers.append((b"Content-Length", b"0")) - - self.headers = Headers(auto_headers + self.headers.raw) - - @property - def content(self) -> bytes: - if not hasattr(self, "_content"): - raise RequestNotRead() - return self._content - - def read(self) -> bytes: - """ - Read and return the request content. - """ - if not hasattr(self, "_content"): - assert isinstance(self.stream, typing.Iterable) - self._content = b"".join(self.stream) - if not isinstance(self.stream, ByteStream): - # If a streaming request has been read entirely into memory, then - # we can replace the stream with a raw bytes implementation, - # to ensure that any non-replayable streams can still be used. - self.stream = ByteStream(self._content) - return self._content - - async def aread(self) -> bytes: - """ - Read and return the request content. - """ - if not hasattr(self, "_content"): - assert isinstance(self.stream, typing.AsyncIterable) - self._content = b"".join([part async for part in self.stream]) - if not isinstance(self.stream, ByteStream): - # If a streaming request has been read entirely into memory, then - # we can replace the stream with a raw bytes implementation, - # to ensure that any non-replayable streams can still be used. - self.stream = ByteStream(self._content) - return self._content - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - url = str(self.url) - return f"<{class_name}({self.method!r}, {url!r})>" - - def __getstate__(self) -> dict[str, typing.Any]: - return { - name: value - for name, value in self.__dict__.items() - if name not in ["extensions", "stream"] - } - - def __setstate__(self, state: dict[str, typing.Any]) -> None: - for name, value in state.items(): - setattr(self, name, value) - self.extensions = {} - self.stream = UnattachedStream() - - -class Response: - def __init__( - self, - status_code: int, - *, - headers: HeaderTypes | None = None, - content: ResponseContent | None = None, - text: str | None = None, - html: str | None = None, - json: typing.Any = None, - stream: SyncByteStream | AsyncByteStream | None = None, - request: Request | None = None, - extensions: ResponseExtensions | None = None, - history: list[Response] | None = None, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - self.status_code = status_code - self.headers = Headers(headers) - - self._request: Request | None = request - - # When follow_redirects=False and a redirect is received, - # the client will set `response.next_request`. - self.next_request: Request | None = None - - self.extensions = {} if extensions is None else dict(extensions) - self.history = [] if history is None else list(history) - - self.is_closed = False - self.is_stream_consumed = False - - self.default_encoding = default_encoding - - if stream is None: - headers, stream = encode_response(content, text, html, json) - self._prepare(headers) - self.stream = stream - if isinstance(stream, ByteStream): - # Load the response body, except for streaming content. - self.read() - else: - # There's an important distinction between `Response(content=...)`, - # and `Response(stream=...)`. - # - # Using `content=...` implies automatically populated content headers, - # of either `Content-Length: ...` or `Transfer-Encoding: chunked`. - # - # Using `stream=...` will not automatically include any content headers. - # - # As an end-user you don't really need `stream=...`. It's only - # useful when creating response instances having received a stream - # from the transport API. - self.stream = stream - - self._num_bytes_downloaded = 0 - - def _prepare(self, default_headers: dict[str, str]) -> None: - for key, value in default_headers.items(): - # Ignore Transfer-Encoding if the Content-Length has been set explicitly. - if key.lower() == "transfer-encoding" and "content-length" in self.headers: - continue - self.headers.setdefault(key, value) - - @property - def elapsed(self) -> datetime.timedelta: - """ - Returns the time taken for the complete request/response - cycle to complete. - """ - if not hasattr(self, "_elapsed"): - raise RuntimeError( - "'.elapsed' may only be accessed after the response " - "has been read or closed." - ) - return self._elapsed - - @elapsed.setter - def elapsed(self, elapsed: datetime.timedelta) -> None: - self._elapsed = elapsed - - @property - def request(self) -> Request: - """ - Returns the request instance associated to the current response. - """ - if self._request is None: - raise RuntimeError( - "The request instance has not been set on this response." - ) - return self._request - - @request.setter - def request(self, value: Request) -> None: - self._request = value - - @property - def http_version(self) -> str: - try: - http_version: bytes = self.extensions["http_version"] - except KeyError: - return "HTTP/1.1" - else: - return http_version.decode("ascii", errors="ignore") - - @property - def reason_phrase(self) -> str: - try: - reason_phrase: bytes = self.extensions["reason_phrase"] - except KeyError: - return codes.get_reason_phrase(self.status_code) - else: - return reason_phrase.decode("ascii", errors="ignore") - - @property - def url(self) -> URL: - """ - Returns the URL for which the request was made. - """ - return self.request.url - - @property - def content(self) -> bytes: - if not hasattr(self, "_content"): - raise ResponseNotRead() - return self._content - - @property - def text(self) -> str: - if not hasattr(self, "_text"): - content = self.content - if not content: - self._text = "" - else: - decoder = TextDecoder(encoding=self.encoding or "utf-8") - self._text = "".join([decoder.decode(self.content), decoder.flush()]) - return self._text - - @property - def encoding(self) -> str | None: - """ - Return an encoding to use for decoding the byte content into text. - The priority for determining this is given by... - - * `.encoding = <>` has been set explicitly. - * The encoding as specified by the charset parameter in the Content-Type header. - * The encoding as determined by `default_encoding`, which may either be - a string like "utf-8" indicating the encoding to use, or may be a callable - which enables charset autodetection. - """ - if not hasattr(self, "_encoding"): - encoding = self.charset_encoding - if encoding is None or not _is_known_encoding(encoding): - if isinstance(self.default_encoding, str): - encoding = self.default_encoding - elif hasattr(self, "_content"): - encoding = self.default_encoding(self._content) - self._encoding = encoding or "utf-8" - return self._encoding - - @encoding.setter - def encoding(self, value: str) -> None: - """ - Set the encoding to use for decoding the byte content into text. - - If the `text` attribute has been accessed, attempting to set the - encoding will throw a ValueError. - """ - if hasattr(self, "_text"): - raise ValueError( - "Setting encoding after `text` has been accessed is not allowed." - ) - self._encoding = value - - @property - def charset_encoding(self) -> str | None: - """ - Return the encoding, as specified by the Content-Type header. - """ - content_type = self.headers.get("Content-Type") - if content_type is None: - return None - - return _parse_content_type_charset(content_type) - - def _get_content_decoder(self) -> ContentDecoder: - """ - Returns a decoder instance which can be used to decode the raw byte - content, depending on the Content-Encoding used in the response. - """ - if not hasattr(self, "_decoder"): - decoders: list[ContentDecoder] = [] - values = self.headers.get_list("content-encoding", split_commas=True) - for value in values: - value = value.strip().lower() - try: - decoder_cls = SUPPORTED_DECODERS[value] - decoders.append(decoder_cls()) - except KeyError: - continue - - if len(decoders) == 1: - self._decoder = decoders[0] - elif len(decoders) > 1: - self._decoder = MultiDecoder(children=decoders) - else: - self._decoder = IdentityDecoder() - - return self._decoder - - @property - def is_informational(self) -> bool: - """ - A property which is `True` for 1xx status codes, `False` otherwise. - """ - return codes.is_informational(self.status_code) - - @property - def is_success(self) -> bool: - """ - A property which is `True` for 2xx status codes, `False` otherwise. - """ - return codes.is_success(self.status_code) - - @property - def is_redirect(self) -> bool: - """ - A property which is `True` for 3xx status codes, `False` otherwise. - - Note that not all responses with a 3xx status code indicate a URL redirect. - - Use `response.has_redirect_location` to determine responses with a properly - formed URL redirection. - """ - return codes.is_redirect(self.status_code) - - @property - def is_client_error(self) -> bool: - """ - A property which is `True` for 4xx status codes, `False` otherwise. - """ - return codes.is_client_error(self.status_code) - - @property - def is_server_error(self) -> bool: - """ - A property which is `True` for 5xx status codes, `False` otherwise. - """ - return codes.is_server_error(self.status_code) - - @property - def is_error(self) -> bool: - """ - A property which is `True` for 4xx and 5xx status codes, `False` otherwise. - """ - return codes.is_error(self.status_code) - - @property - def has_redirect_location(self) -> bool: - """ - Returns True for 3xx responses with a properly formed URL redirection, - `False` otherwise. - """ - return ( - self.status_code - in ( - # 301 (Cacheable redirect. Method may change to GET.) - codes.MOVED_PERMANENTLY, - # 302 (Uncacheable redirect. Method may change to GET.) - codes.FOUND, - # 303 (Client should make a GET or HEAD request.) - codes.SEE_OTHER, - # 307 (Equiv. 302, but retain method) - codes.TEMPORARY_REDIRECT, - # 308 (Equiv. 301, but retain method) - codes.PERMANENT_REDIRECT, - ) - and "Location" in self.headers - ) - - def raise_for_status(self) -> Response: - """ - Raise the `HTTPStatusError` if one occurred. - """ - request = self._request - if request is None: - raise RuntimeError( - "Cannot call `raise_for_status` as the request " - "instance has not been set on this response." - ) - - if self.is_success: - return self - - if self.has_redirect_location: - message = ( - "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n" - "Redirect location: '{0.headers[location]}'\n" - "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}" - ) - else: - message = ( - "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n" - "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}" - ) - - status_class = self.status_code // 100 - error_types = { - 1: "Informational response", - 3: "Redirect response", - 4: "Client error", - 5: "Server error", - } - error_type = error_types.get(status_class, "Invalid status code") - message = message.format(self, error_type=error_type) - raise HTTPStatusError(message, request=request, response=self) - - def json(self, **kwargs: typing.Any) -> typing.Any: - return jsonlib.loads(self.content, **kwargs) - - @property - def cookies(self) -> Cookies: - if not hasattr(self, "_cookies"): - self._cookies = Cookies() - self._cookies.extract_cookies(self) - return self._cookies - - @property - def links(self) -> dict[str | None, dict[str, str]]: - """ - Returns the parsed header links of the response, if any - """ - header = self.headers.get("link") - if header is None: - return {} - - return { - (link.get("rel") or link.get("url")): link - for link in _parse_header_links(header) - } - - @property - def num_bytes_downloaded(self) -> int: - return self._num_bytes_downloaded - - def __repr__(self) -> str: - return f"" - - def __getstate__(self) -> dict[str, typing.Any]: - return { - name: value - for name, value in self.__dict__.items() - if name not in ["extensions", "stream", "is_closed", "_decoder"] - } - - def __setstate__(self, state: dict[str, typing.Any]) -> None: - for name, value in state.items(): - setattr(self, name, value) - self.is_closed = True - self.extensions = {} - self.stream = UnattachedStream() - - def read(self) -> bytes: - """ - Read and return the response content. - """ - if not hasattr(self, "_content"): - self._content = b"".join(self.iter_bytes()) - return self._content - - def iter_bytes(self, chunk_size: int | None = None) -> typing.Iterator[bytes]: - """ - A byte-iterator over the decoded response content. - This allows us to handle gzip, deflate, brotli, and zstd encoded responses. - """ - if hasattr(self, "_content"): - chunk_size = len(self._content) if chunk_size is None else chunk_size - for i in range(0, len(self._content), max(chunk_size, 1)): - yield self._content[i : i + chunk_size] - else: - decoder = self._get_content_decoder() - chunker = ByteChunker(chunk_size=chunk_size) - with request_context(request=self._request): - for raw_bytes in self.iter_raw(): - decoded = decoder.decode(raw_bytes) - for chunk in chunker.decode(decoded): - yield chunk - decoded = decoder.flush() - for chunk in chunker.decode(decoded): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - def iter_text(self, chunk_size: int | None = None) -> typing.Iterator[str]: - """ - A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - decoder = TextDecoder(encoding=self.encoding or "utf-8") - chunker = TextChunker(chunk_size=chunk_size) - with request_context(request=self._request): - for byte_content in self.iter_bytes(): - text_content = decoder.decode(byte_content) - for chunk in chunker.decode(text_content): - yield chunk - text_content = decoder.flush() - for chunk in chunker.decode(text_content): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - def iter_lines(self) -> typing.Iterator[str]: - decoder = LineDecoder() - with request_context(request=self._request): - for text in self.iter_text(): - for line in decoder.decode(text): - yield line - for line in decoder.flush(): - yield line - - def iter_raw(self, chunk_size: int | None = None) -> typing.Iterator[bytes]: - """ - A byte-iterator over the raw response content. - """ - if self.is_stream_consumed: - raise StreamConsumed() - if self.is_closed: - raise StreamClosed() - if not isinstance(self.stream, SyncByteStream): - raise RuntimeError("Attempted to call a sync iterator on an async stream.") - - self.is_stream_consumed = True - self._num_bytes_downloaded = 0 - chunker = ByteChunker(chunk_size=chunk_size) - - with request_context(request=self._request): - for raw_stream_bytes in self.stream: - self._num_bytes_downloaded += len(raw_stream_bytes) - for chunk in chunker.decode(raw_stream_bytes): - yield chunk - - for chunk in chunker.flush(): - yield chunk - - self.close() - - def close(self) -> None: - """ - Close the response and release the connection. - Automatically called if the response body is read to completion. - """ - if not isinstance(self.stream, SyncByteStream): - raise RuntimeError("Attempted to call an sync close on an async stream.") - - if not self.is_closed: - self.is_closed = True - with request_context(request=self._request): - self.stream.close() - - async def aread(self) -> bytes: - """ - Read and return the response content. - """ - if not hasattr(self, "_content"): - self._content = b"".join([part async for part in self.aiter_bytes()]) - return self._content - - async def aiter_bytes( - self, chunk_size: int | None = None - ) -> typing.AsyncIterator[bytes]: - """ - A byte-iterator over the decoded response content. - This allows us to handle gzip, deflate, brotli, and zstd encoded responses. - """ - if hasattr(self, "_content"): - chunk_size = len(self._content) if chunk_size is None else chunk_size - for i in range(0, len(self._content), max(chunk_size, 1)): - yield self._content[i : i + chunk_size] - else: - decoder = self._get_content_decoder() - chunker = ByteChunker(chunk_size=chunk_size) - with request_context(request=self._request): - async for raw_bytes in self.aiter_raw(): - decoded = decoder.decode(raw_bytes) - for chunk in chunker.decode(decoded): - yield chunk - decoded = decoder.flush() - for chunk in chunker.decode(decoded): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - async def aiter_text( - self, chunk_size: int | None = None - ) -> typing.AsyncIterator[str]: - """ - A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - decoder = TextDecoder(encoding=self.encoding or "utf-8") - chunker = TextChunker(chunk_size=chunk_size) - with request_context(request=self._request): - async for byte_content in self.aiter_bytes(): - text_content = decoder.decode(byte_content) - for chunk in chunker.decode(text_content): - yield chunk - text_content = decoder.flush() - for chunk in chunker.decode(text_content): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - async def aiter_lines(self) -> typing.AsyncIterator[str]: - decoder = LineDecoder() - with request_context(request=self._request): - async for text in self.aiter_text(): - for line in decoder.decode(text): - yield line - for line in decoder.flush(): - yield line - - async def aiter_raw( - self, chunk_size: int | None = None - ) -> typing.AsyncIterator[bytes]: - """ - A byte-iterator over the raw response content. - """ - if self.is_stream_consumed: - raise StreamConsumed() - if self.is_closed: - raise StreamClosed() - if not isinstance(self.stream, AsyncByteStream): - raise RuntimeError("Attempted to call an async iterator on an sync stream.") - - self.is_stream_consumed = True - self._num_bytes_downloaded = 0 - chunker = ByteChunker(chunk_size=chunk_size) - - with request_context(request=self._request): - async for raw_stream_bytes in self.stream: - self._num_bytes_downloaded += len(raw_stream_bytes) - for chunk in chunker.decode(raw_stream_bytes): - yield chunk - - for chunk in chunker.flush(): - yield chunk - - await self.aclose() - - async def aclose(self) -> None: - """ - Close the response and release the connection. - Automatically called if the response body is read to completion. - """ - if not isinstance(self.stream, AsyncByteStream): - raise RuntimeError("Attempted to call an async close on an sync stream.") - - if not self.is_closed: - self.is_closed = True - with request_context(request=self._request): - await self.stream.aclose() - - -class Cookies(typing.MutableMapping[str, str]): - """ - HTTP Cookies, as a mutable mapping. - """ - - def __init__(self, cookies: CookieTypes | None = None) -> None: - if cookies is None or isinstance(cookies, dict): - self.jar = CookieJar() - if isinstance(cookies, dict): - for key, value in cookies.items(): - self.set(key, value) - elif isinstance(cookies, list): - self.jar = CookieJar() - for key, value in cookies: - self.set(key, value) - elif isinstance(cookies, Cookies): - self.jar = CookieJar() - for cookie in cookies.jar: - self.jar.set_cookie(cookie) - else: - self.jar = cookies - - def extract_cookies(self, response: Response) -> None: - """ - Loads any cookies based on the response `Set-Cookie` headers. - """ - urllib_response = self._CookieCompatResponse(response) - urllib_request = self._CookieCompatRequest(response.request) - - self.jar.extract_cookies(urllib_response, urllib_request) # type: ignore - - def set_cookie_header(self, request: Request) -> None: - """ - Sets an appropriate 'Cookie:' HTTP header on the `Request`. - """ - urllib_request = self._CookieCompatRequest(request) - self.jar.add_cookie_header(urllib_request) - - def set(self, name: str, value: str, domain: str = "", path: str = "/") -> None: - """ - Set a cookie value by name. May optionally include domain and path. - """ - kwargs = { - "version": 0, - "name": name, - "value": value, - "port": None, - "port_specified": False, - "domain": domain, - "domain_specified": bool(domain), - "domain_initial_dot": domain.startswith("."), - "path": path, - "path_specified": bool(path), - "secure": False, - "expires": None, - "discard": True, - "comment": None, - "comment_url": None, - "rest": {"HttpOnly": None}, - "rfc2109": False, - } - cookie = Cookie(**kwargs) # type: ignore - self.jar.set_cookie(cookie) - - def get( # type: ignore - self, - name: str, - default: str | None = None, - domain: str | None = None, - path: str | None = None, - ) -> str | None: - """ - Get a cookie by name. May optionally include domain and path - in order to specify exactly which cookie to retrieve. - """ - value = None - for cookie in self.jar: - if cookie.name == name: - if domain is None or cookie.domain == domain: - if path is None or cookie.path == path: - if value is not None: - message = f"Multiple cookies exist with name={name}" - raise CookieConflict(message) - value = cookie.value - - if value is None: - return default - return value - - def delete( - self, - name: str, - domain: str | None = None, - path: str | None = None, - ) -> None: - """ - Delete a cookie by name. May optionally include domain and path - in order to specify exactly which cookie to delete. - """ - if domain is not None and path is not None: - return self.jar.clear(domain, path, name) - - remove = [ - cookie - for cookie in self.jar - if cookie.name == name - and (domain is None or cookie.domain == domain) - and (path is None or cookie.path == path) - ] - - for cookie in remove: - self.jar.clear(cookie.domain, cookie.path, cookie.name) - - def clear(self, domain: str | None = None, path: str | None = None) -> None: - """ - Delete all cookies. Optionally include a domain and path in - order to only delete a subset of all the cookies. - """ - args = [] - if domain is not None: - args.append(domain) - if path is not None: - assert domain is not None - args.append(path) - self.jar.clear(*args) - - def update(self, cookies: CookieTypes | None = None) -> None: # type: ignore - cookies = Cookies(cookies) - for cookie in cookies.jar: - self.jar.set_cookie(cookie) - - def __setitem__(self, name: str, value: str) -> None: - return self.set(name, value) - - def __getitem__(self, name: str) -> str: - value = self.get(name) - if value is None: - raise KeyError(name) - return value - - def __delitem__(self, name: str) -> None: - return self.delete(name) - - def __len__(self) -> int: - return len(self.jar) - - def __iter__(self) -> typing.Iterator[str]: - return (cookie.name for cookie in self.jar) - - def __bool__(self) -> bool: - for _ in self.jar: - return True - return False - - def __repr__(self) -> str: - cookies_repr = ", ".join( - [ - f"" - for cookie in self.jar - ] - ) - - return f"" - - class _CookieCompatRequest(urllib.request.Request): - """ - Wraps a `Request` instance up in a compatibility interface suitable - for use with `CookieJar` operations. - """ - - def __init__(self, request: Request) -> None: - super().__init__( - url=str(request.url), - headers=dict(request.headers), - method=request.method, - ) - self.request = request - - def add_unredirected_header(self, key: str, value: str) -> None: - super().add_unredirected_header(key, value) - self.request.headers[key] = value - - class _CookieCompatResponse: - """ - Wraps a `Request` instance up in a compatibility interface suitable - for use with `CookieJar` operations. - """ - - def __init__(self, response: Response) -> None: - self.response = response - - def info(self) -> email.message.Message: - info = email.message.Message() - for key, value in self.response.headers.multi_items(): - # Note that setting `info[key]` here is an "append" operation, - # not a "replace" operation. - # https://docs.python.org/3/library/email.compat32-message.html#email.message.Message.__setitem__ - info[key] = value - return info diff --git a/venv/lib/python3.10/site-packages/httpx/_multipart.py b/venv/lib/python3.10/site-packages/httpx/_multipart.py deleted file mode 100644 index b4761af9b2cf384de5189269927d781a700dbe46..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_multipart.py +++ /dev/null @@ -1,300 +0,0 @@ -from __future__ import annotations - -import io -import mimetypes -import os -import re -import typing -from pathlib import Path - -from ._types import ( - AsyncByteStream, - FileContent, - FileTypes, - RequestData, - RequestFiles, - SyncByteStream, -) -from ._utils import ( - peek_filelike_length, - primitive_value_to_str, - to_bytes, -) - -_HTML5_FORM_ENCODING_REPLACEMENTS = {'"': "%22", "\\": "\\\\"} -_HTML5_FORM_ENCODING_REPLACEMENTS.update( - {chr(c): "%{:02X}".format(c) for c in range(0x1F + 1) if c != 0x1B} -) -_HTML5_FORM_ENCODING_RE = re.compile( - r"|".join([re.escape(c) for c in _HTML5_FORM_ENCODING_REPLACEMENTS.keys()]) -) - - -def _format_form_param(name: str, value: str) -> bytes: - """ - Encode a name/value pair within a multipart form. - """ - - def replacer(match: typing.Match[str]) -> str: - return _HTML5_FORM_ENCODING_REPLACEMENTS[match.group(0)] - - value = _HTML5_FORM_ENCODING_RE.sub(replacer, value) - return f'{name}="{value}"'.encode() - - -def _guess_content_type(filename: str | None) -> str | None: - """ - Guesses the mimetype based on a filename. Defaults to `application/octet-stream`. - - Returns `None` if `filename` is `None` or empty. - """ - if filename: - return mimetypes.guess_type(filename)[0] or "application/octet-stream" - return None - - -def get_multipart_boundary_from_content_type( - content_type: bytes | None, -) -> bytes | None: - if not content_type or not content_type.startswith(b"multipart/form-data"): - return None - # parse boundary according to - # https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1 - if b";" in content_type: - for section in content_type.split(b";"): - if section.strip().lower().startswith(b"boundary="): - return section.strip()[len(b"boundary=") :].strip(b'"') - return None - - -class DataField: - """ - A single form field item, within a multipart form field. - """ - - def __init__(self, name: str, value: str | bytes | int | float | None) -> None: - if not isinstance(name, str): - raise TypeError( - f"Invalid type for name. Expected str, got {type(name)}: {name!r}" - ) - if value is not None and not isinstance(value, (str, bytes, int, float)): - raise TypeError( - "Invalid type for value. Expected primitive type," - f" got {type(value)}: {value!r}" - ) - self.name = name - self.value: str | bytes = ( - value if isinstance(value, bytes) else primitive_value_to_str(value) - ) - - def render_headers(self) -> bytes: - if not hasattr(self, "_headers"): - name = _format_form_param("name", self.name) - self._headers = b"".join( - [b"Content-Disposition: form-data; ", name, b"\r\n\r\n"] - ) - - return self._headers - - def render_data(self) -> bytes: - if not hasattr(self, "_data"): - self._data = to_bytes(self.value) - - return self._data - - def get_length(self) -> int: - headers = self.render_headers() - data = self.render_data() - return len(headers) + len(data) - - def render(self) -> typing.Iterator[bytes]: - yield self.render_headers() - yield self.render_data() - - -class FileField: - """ - A single file field item, within a multipart form field. - """ - - CHUNK_SIZE = 64 * 1024 - - def __init__(self, name: str, value: FileTypes) -> None: - self.name = name - - fileobj: FileContent - - headers: dict[str, str] = {} - content_type: str | None = None - - # This large tuple based API largely mirror's requests' API - # It would be good to think of better APIs for this that we could - # include in httpx 2.0 since variable length tuples(especially of 4 elements) - # are quite unwieldly - if isinstance(value, tuple): - if len(value) == 2: - # neither the 3rd parameter (content_type) nor the 4th (headers) - # was included - filename, fileobj = value - elif len(value) == 3: - filename, fileobj, content_type = value - else: - # all 4 parameters included - filename, fileobj, content_type, headers = value # type: ignore - else: - filename = Path(str(getattr(value, "name", "upload"))).name - fileobj = value - - if content_type is None: - content_type = _guess_content_type(filename) - - has_content_type_header = any("content-type" in key.lower() for key in headers) - if content_type is not None and not has_content_type_header: - # note that unlike requests, we ignore the content_type provided in the 3rd - # tuple element if it is also included in the headers requests does - # the opposite (it overwrites the headerwith the 3rd tuple element) - headers["Content-Type"] = content_type - - if isinstance(fileobj, io.StringIO): - raise TypeError( - "Multipart file uploads require 'io.BytesIO', not 'io.StringIO'." - ) - if isinstance(fileobj, io.TextIOBase): - raise TypeError( - "Multipart file uploads must be opened in binary mode, not text mode." - ) - - self.filename = filename - self.file = fileobj - self.headers = headers - - def get_length(self) -> int | None: - headers = self.render_headers() - - if isinstance(self.file, (str, bytes)): - return len(headers) + len(to_bytes(self.file)) - - file_length = peek_filelike_length(self.file) - - # If we can't determine the filesize without reading it into memory, - # then return `None` here, to indicate an unknown file length. - if file_length is None: - return None - - return len(headers) + file_length - - def render_headers(self) -> bytes: - if not hasattr(self, "_headers"): - parts = [ - b"Content-Disposition: form-data; ", - _format_form_param("name", self.name), - ] - if self.filename: - filename = _format_form_param("filename", self.filename) - parts.extend([b"; ", filename]) - for header_name, header_value in self.headers.items(): - key, val = f"\r\n{header_name}: ".encode(), header_value.encode() - parts.extend([key, val]) - parts.append(b"\r\n\r\n") - self._headers = b"".join(parts) - - return self._headers - - def render_data(self) -> typing.Iterator[bytes]: - if isinstance(self.file, (str, bytes)): - yield to_bytes(self.file) - return - - if hasattr(self.file, "seek"): - try: - self.file.seek(0) - except io.UnsupportedOperation: - pass - - chunk = self.file.read(self.CHUNK_SIZE) - while chunk: - yield to_bytes(chunk) - chunk = self.file.read(self.CHUNK_SIZE) - - def render(self) -> typing.Iterator[bytes]: - yield self.render_headers() - yield from self.render_data() - - -class MultipartStream(SyncByteStream, AsyncByteStream): - """ - Request content as streaming multipart encoded form data. - """ - - def __init__( - self, - data: RequestData, - files: RequestFiles, - boundary: bytes | None = None, - ) -> None: - if boundary is None: - boundary = os.urandom(16).hex().encode("ascii") - - self.boundary = boundary - self.content_type = "multipart/form-data; boundary=%s" % boundary.decode( - "ascii" - ) - self.fields = list(self._iter_fields(data, files)) - - def _iter_fields( - self, data: RequestData, files: RequestFiles - ) -> typing.Iterator[FileField | DataField]: - for name, value in data.items(): - if isinstance(value, (tuple, list)): - for item in value: - yield DataField(name=name, value=item) - else: - yield DataField(name=name, value=value) - - file_items = files.items() if isinstance(files, typing.Mapping) else files - for name, value in file_items: - yield FileField(name=name, value=value) - - def iter_chunks(self) -> typing.Iterator[bytes]: - for field in self.fields: - yield b"--%s\r\n" % self.boundary - yield from field.render() - yield b"\r\n" - yield b"--%s--\r\n" % self.boundary - - def get_content_length(self) -> int | None: - """ - Return the length of the multipart encoded content, or `None` if - any of the files have a length that cannot be determined upfront. - """ - boundary_length = len(self.boundary) - length = 0 - - for field in self.fields: - field_length = field.get_length() - if field_length is None: - return None - - length += 2 + boundary_length + 2 # b"--{boundary}\r\n" - length += field_length - length += 2 # b"\r\n" - - length += 2 + boundary_length + 4 # b"--{boundary}--\r\n" - return length - - # Content stream interface. - - def get_headers(self) -> dict[str, str]: - content_length = self.get_content_length() - content_type = self.content_type - if content_length is None: - return {"Transfer-Encoding": "chunked", "Content-Type": content_type} - return {"Content-Length": str(content_length), "Content-Type": content_type} - - def __iter__(self) -> typing.Iterator[bytes]: - for chunk in self.iter_chunks(): - yield chunk - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - for chunk in self.iter_chunks(): - yield chunk diff --git a/venv/lib/python3.10/site-packages/httpx/_status_codes.py b/venv/lib/python3.10/site-packages/httpx/_status_codes.py deleted file mode 100644 index 133a6231a5b53fd2f073799ca1bd07c50abe40ae..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_status_codes.py +++ /dev/null @@ -1,162 +0,0 @@ -from __future__ import annotations - -from enum import IntEnum - -__all__ = ["codes"] - - -class codes(IntEnum): - """HTTP status codes and reason phrases - - Status codes from the following RFCs are all observed: - - * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 - * RFC 6585: Additional HTTP Status Codes - * RFC 3229: Delta encoding in HTTP - * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518 - * RFC 5842: Binding Extensions to WebDAV - * RFC 7238: Permanent Redirect - * RFC 2295: Transparent Content Negotiation in HTTP - * RFC 2774: An HTTP Extension Framework - * RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2) - * RFC 2324: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) - * RFC 7725: An HTTP Status Code to Report Legal Obstacles - * RFC 8297: An HTTP Status Code for Indicating Hints - * RFC 8470: Using Early Data in HTTP - """ - - def __new__(cls, value: int, phrase: str = "") -> codes: - obj = int.__new__(cls, value) - obj._value_ = value - - obj.phrase = phrase # type: ignore[attr-defined] - return obj - - def __str__(self) -> str: - return str(self.value) - - @classmethod - def get_reason_phrase(cls, value: int) -> str: - try: - return codes(value).phrase # type: ignore - except ValueError: - return "" - - @classmethod - def is_informational(cls, value: int) -> bool: - """ - Returns `True` for 1xx status codes, `False` otherwise. - """ - return 100 <= value <= 199 - - @classmethod - def is_success(cls, value: int) -> bool: - """ - Returns `True` for 2xx status codes, `False` otherwise. - """ - return 200 <= value <= 299 - - @classmethod - def is_redirect(cls, value: int) -> bool: - """ - Returns `True` for 3xx status codes, `False` otherwise. - """ - return 300 <= value <= 399 - - @classmethod - def is_client_error(cls, value: int) -> bool: - """ - Returns `True` for 4xx status codes, `False` otherwise. - """ - return 400 <= value <= 499 - - @classmethod - def is_server_error(cls, value: int) -> bool: - """ - Returns `True` for 5xx status codes, `False` otherwise. - """ - return 500 <= value <= 599 - - @classmethod - def is_error(cls, value: int) -> bool: - """ - Returns `True` for 4xx or 5xx status codes, `False` otherwise. - """ - return 400 <= value <= 599 - - # informational - CONTINUE = 100, "Continue" - SWITCHING_PROTOCOLS = 101, "Switching Protocols" - PROCESSING = 102, "Processing" - EARLY_HINTS = 103, "Early Hints" - - # success - OK = 200, "OK" - CREATED = 201, "Created" - ACCEPTED = 202, "Accepted" - NON_AUTHORITATIVE_INFORMATION = 203, "Non-Authoritative Information" - NO_CONTENT = 204, "No Content" - RESET_CONTENT = 205, "Reset Content" - PARTIAL_CONTENT = 206, "Partial Content" - MULTI_STATUS = 207, "Multi-Status" - ALREADY_REPORTED = 208, "Already Reported" - IM_USED = 226, "IM Used" - - # redirection - MULTIPLE_CHOICES = 300, "Multiple Choices" - MOVED_PERMANENTLY = 301, "Moved Permanently" - FOUND = 302, "Found" - SEE_OTHER = 303, "See Other" - NOT_MODIFIED = 304, "Not Modified" - USE_PROXY = 305, "Use Proxy" - TEMPORARY_REDIRECT = 307, "Temporary Redirect" - PERMANENT_REDIRECT = 308, "Permanent Redirect" - - # client error - BAD_REQUEST = 400, "Bad Request" - UNAUTHORIZED = 401, "Unauthorized" - PAYMENT_REQUIRED = 402, "Payment Required" - FORBIDDEN = 403, "Forbidden" - NOT_FOUND = 404, "Not Found" - METHOD_NOT_ALLOWED = 405, "Method Not Allowed" - NOT_ACCEPTABLE = 406, "Not Acceptable" - PROXY_AUTHENTICATION_REQUIRED = 407, "Proxy Authentication Required" - REQUEST_TIMEOUT = 408, "Request Timeout" - CONFLICT = 409, "Conflict" - GONE = 410, "Gone" - LENGTH_REQUIRED = 411, "Length Required" - PRECONDITION_FAILED = 412, "Precondition Failed" - REQUEST_ENTITY_TOO_LARGE = 413, "Request Entity Too Large" - REQUEST_URI_TOO_LONG = 414, "Request-URI Too Long" - UNSUPPORTED_MEDIA_TYPE = 415, "Unsupported Media Type" - REQUESTED_RANGE_NOT_SATISFIABLE = 416, "Requested Range Not Satisfiable" - EXPECTATION_FAILED = 417, "Expectation Failed" - IM_A_TEAPOT = 418, "I'm a teapot" - MISDIRECTED_REQUEST = 421, "Misdirected Request" - UNPROCESSABLE_ENTITY = 422, "Unprocessable Entity" - LOCKED = 423, "Locked" - FAILED_DEPENDENCY = 424, "Failed Dependency" - TOO_EARLY = 425, "Too Early" - UPGRADE_REQUIRED = 426, "Upgrade Required" - PRECONDITION_REQUIRED = 428, "Precondition Required" - TOO_MANY_REQUESTS = 429, "Too Many Requests" - REQUEST_HEADER_FIELDS_TOO_LARGE = 431, "Request Header Fields Too Large" - UNAVAILABLE_FOR_LEGAL_REASONS = 451, "Unavailable For Legal Reasons" - - # server errors - INTERNAL_SERVER_ERROR = 500, "Internal Server Error" - NOT_IMPLEMENTED = 501, "Not Implemented" - BAD_GATEWAY = 502, "Bad Gateway" - SERVICE_UNAVAILABLE = 503, "Service Unavailable" - GATEWAY_TIMEOUT = 504, "Gateway Timeout" - HTTP_VERSION_NOT_SUPPORTED = 505, "HTTP Version Not Supported" - VARIANT_ALSO_NEGOTIATES = 506, "Variant Also Negotiates" - INSUFFICIENT_STORAGE = 507, "Insufficient Storage" - LOOP_DETECTED = 508, "Loop Detected" - NOT_EXTENDED = 510, "Not Extended" - NETWORK_AUTHENTICATION_REQUIRED = 511, "Network Authentication Required" - - -# Include lower-case styles for `requests` compatibility. -for code in codes: - setattr(codes, code._name_.lower(), int(code)) diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/__init__.py b/venv/lib/python3.10/site-packages/httpx/_transports/__init__.py deleted file mode 100644 index 7a321053b29bcd48698cf2bd74a1d19c8556aefb..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_transports/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from .asgi import * -from .base import * -from .default import * -from .mock import * -from .wsgi import * - -__all__ = [ - "ASGITransport", - "AsyncBaseTransport", - "BaseTransport", - "AsyncHTTPTransport", - "HTTPTransport", - "MockTransport", - "WSGITransport", -] diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 850ffa33a354fc15bccab2dc6cdf12ecb41d1e92..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/asgi.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/asgi.cpython-310.pyc deleted file mode 100644 index 10dc7e1977b05bd384884020faeecc2a9261a142..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/asgi.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/base.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/base.cpython-310.pyc deleted file mode 100644 index 108ad110cace417b122b8ada300fd13b29747f85..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/base.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/default.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/default.cpython-310.pyc deleted file mode 100644 index a89f3621d122515dc9b2e8754643c9079db2cc45..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/default.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/mock.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/mock.cpython-310.pyc deleted file mode 100644 index 0b8feca610a0a3faac148557b35cdf9645149c29..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/mock.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/wsgi.cpython-310.pyc b/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/wsgi.cpython-310.pyc deleted file mode 100644 index 7a480f36985d0792552e62ad240fab021f2cf7e6..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/httpx/_transports/__pycache__/wsgi.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/asgi.py b/venv/lib/python3.10/site-packages/httpx/_transports/asgi.py deleted file mode 100644 index 2bc4efae0e1b14620f75f712eb15ecf500d14eef..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_transports/asgi.py +++ /dev/null @@ -1,187 +0,0 @@ -from __future__ import annotations - -import typing - -from .._models import Request, Response -from .._types import AsyncByteStream -from .base import AsyncBaseTransport - -if typing.TYPE_CHECKING: # pragma: no cover - import asyncio - - import trio - - Event = typing.Union[asyncio.Event, trio.Event] - - -_Message = typing.MutableMapping[str, typing.Any] -_Receive = typing.Callable[[], typing.Awaitable[_Message]] -_Send = typing.Callable[ - [typing.MutableMapping[str, typing.Any]], typing.Awaitable[None] -] -_ASGIApp = typing.Callable[ - [typing.MutableMapping[str, typing.Any], _Receive, _Send], typing.Awaitable[None] -] - -__all__ = ["ASGITransport"] - - -def is_running_trio() -> bool: - try: - # sniffio is a dependency of trio. - - # See https://github.com/python-trio/trio/issues/2802 - import sniffio - - if sniffio.current_async_library() == "trio": - return True - except ImportError: # pragma: nocover - pass - - return False - - -def create_event() -> Event: - if is_running_trio(): - import trio - - return trio.Event() - - import asyncio - - return asyncio.Event() - - -class ASGIResponseStream(AsyncByteStream): - def __init__(self, body: list[bytes]) -> None: - self._body = body - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - yield b"".join(self._body) - - -class ASGITransport(AsyncBaseTransport): - """ - A custom AsyncTransport that handles sending requests directly to an ASGI app. - - ```python - transport = httpx.ASGITransport( - app=app, - root_path="/submount", - client=("1.2.3.4", 123) - ) - client = httpx.AsyncClient(transport=transport) - ``` - - Arguments: - - * `app` - The ASGI application. - * `raise_app_exceptions` - Boolean indicating if exceptions in the application - should be raised. Default to `True`. Can be set to `False` for use cases - such as testing the content of a client 500 response. - * `root_path` - The root path on which the ASGI application should be mounted. - * `client` - A two-tuple indicating the client IP and port of incoming requests. - ``` - """ - - def __init__( - self, - app: _ASGIApp, - raise_app_exceptions: bool = True, - root_path: str = "", - client: tuple[str, int] = ("127.0.0.1", 123), - ) -> None: - self.app = app - self.raise_app_exceptions = raise_app_exceptions - self.root_path = root_path - self.client = client - - async def handle_async_request( - self, - request: Request, - ) -> Response: - assert isinstance(request.stream, AsyncByteStream) - - # ASGI scope. - scope = { - "type": "http", - "asgi": {"version": "3.0"}, - "http_version": "1.1", - "method": request.method, - "headers": [(k.lower(), v) for (k, v) in request.headers.raw], - "scheme": request.url.scheme, - "path": request.url.path, - "raw_path": request.url.raw_path.split(b"?")[0], - "query_string": request.url.query, - "server": (request.url.host, request.url.port), - "client": self.client, - "root_path": self.root_path, - } - - # Request. - request_body_chunks = request.stream.__aiter__() - request_complete = False - - # Response. - status_code = None - response_headers = None - body_parts = [] - response_started = False - response_complete = create_event() - - # ASGI callables. - - async def receive() -> dict[str, typing.Any]: - nonlocal request_complete - - if request_complete: - await response_complete.wait() - return {"type": "http.disconnect"} - - try: - body = await request_body_chunks.__anext__() - except StopAsyncIteration: - request_complete = True - return {"type": "http.request", "body": b"", "more_body": False} - return {"type": "http.request", "body": body, "more_body": True} - - async def send(message: typing.MutableMapping[str, typing.Any]) -> None: - nonlocal status_code, response_headers, response_started - - if message["type"] == "http.response.start": - assert not response_started - - status_code = message["status"] - response_headers = message.get("headers", []) - response_started = True - - elif message["type"] == "http.response.body": - assert not response_complete.is_set() - body = message.get("body", b"") - more_body = message.get("more_body", False) - - if body and request.method != "HEAD": - body_parts.append(body) - - if not more_body: - response_complete.set() - - try: - await self.app(scope, receive, send) - except Exception: # noqa: PIE-786 - if self.raise_app_exceptions: - raise - - response_complete.set() - if status_code is None: - status_code = 500 - if response_headers is None: - response_headers = {} - - assert response_complete.is_set() - assert status_code is not None - assert response_headers is not None - - stream = ASGIResponseStream(body_parts) - - return Response(status_code, headers=response_headers, stream=stream) diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/base.py b/venv/lib/python3.10/site-packages/httpx/_transports/base.py deleted file mode 100644 index 66fd99d702480b555c06694fe14715ea6df3dfc3..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_transports/base.py +++ /dev/null @@ -1,86 +0,0 @@ -from __future__ import annotations - -import typing -from types import TracebackType - -from .._models import Request, Response - -T = typing.TypeVar("T", bound="BaseTransport") -A = typing.TypeVar("A", bound="AsyncBaseTransport") - -__all__ = ["AsyncBaseTransport", "BaseTransport"] - - -class BaseTransport: - def __enter__(self: T) -> T: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - self.close() - - def handle_request(self, request: Request) -> Response: - """ - Send a single HTTP request and return a response. - - Developers shouldn't typically ever need to call into this API directly, - since the Client class provides all the higher level user-facing API - niceties. - - In order to properly release any network resources, the response - stream should *either* be consumed immediately, with a call to - `response.stream.read()`, or else the `handle_request` call should - be followed with a try/finally block to ensuring the stream is - always closed. - - Example usage: - - with httpx.HTTPTransport() as transport: - req = httpx.Request( - method=b"GET", - url=(b"https", b"www.example.com", 443, b"/"), - headers=[(b"Host", b"www.example.com")], - ) - resp = transport.handle_request(req) - body = resp.stream.read() - print(resp.status_code, resp.headers, body) - - - Takes a `Request` instance as the only argument. - - Returns a `Response` instance. - """ - raise NotImplementedError( - "The 'handle_request' method must be implemented." - ) # pragma: no cover - - def close(self) -> None: - pass - - -class AsyncBaseTransport: - async def __aenter__(self: A) -> A: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - await self.aclose() - - async def handle_async_request( - self, - request: Request, - ) -> Response: - raise NotImplementedError( - "The 'handle_async_request' method must be implemented." - ) # pragma: no cover - - async def aclose(self) -> None: - pass diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/default.py b/venv/lib/python3.10/site-packages/httpx/_transports/default.py deleted file mode 100644 index d5aa05ff234fd3fbf4fee88c4a7d3e3c151a538f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_transports/default.py +++ /dev/null @@ -1,406 +0,0 @@ -""" -Custom transports, with nicely configured defaults. - -The following additional keyword arguments are currently supported by httpcore... - -* uds: str -* local_address: str -* retries: int - -Example usages... - -# Disable HTTP/2 on a single specific domain. -mounts = { - "all://": httpx.HTTPTransport(http2=True), - "all://*example.org": httpx.HTTPTransport() -} - -# Using advanced httpcore configuration, with connection retries. -transport = httpx.HTTPTransport(retries=1) -client = httpx.Client(transport=transport) - -# Using advanced httpcore configuration, with unix domain sockets. -transport = httpx.HTTPTransport(uds="socket.uds") -client = httpx.Client(transport=transport) -""" - -from __future__ import annotations - -import contextlib -import typing -from types import TracebackType - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - - import httpx # pragma: no cover - -from .._config import DEFAULT_LIMITS, Limits, Proxy, create_ssl_context -from .._exceptions import ( - ConnectError, - ConnectTimeout, - LocalProtocolError, - NetworkError, - PoolTimeout, - ProtocolError, - ProxyError, - ReadError, - ReadTimeout, - RemoteProtocolError, - TimeoutException, - UnsupportedProtocol, - WriteError, - WriteTimeout, -) -from .._models import Request, Response -from .._types import AsyncByteStream, CertTypes, ProxyTypes, SyncByteStream -from .._urls import URL -from .base import AsyncBaseTransport, BaseTransport - -T = typing.TypeVar("T", bound="HTTPTransport") -A = typing.TypeVar("A", bound="AsyncHTTPTransport") - -SOCKET_OPTION = typing.Union[ - typing.Tuple[int, int, int], - typing.Tuple[int, int, typing.Union[bytes, bytearray]], - typing.Tuple[int, int, None, int], -] - -__all__ = ["AsyncHTTPTransport", "HTTPTransport"] - -HTTPCORE_EXC_MAP: dict[type[Exception], type[httpx.HTTPError]] = {} - - -def _load_httpcore_exceptions() -> dict[type[Exception], type[httpx.HTTPError]]: - import httpcore - - return { - httpcore.TimeoutException: TimeoutException, - httpcore.ConnectTimeout: ConnectTimeout, - httpcore.ReadTimeout: ReadTimeout, - httpcore.WriteTimeout: WriteTimeout, - httpcore.PoolTimeout: PoolTimeout, - httpcore.NetworkError: NetworkError, - httpcore.ConnectError: ConnectError, - httpcore.ReadError: ReadError, - httpcore.WriteError: WriteError, - httpcore.ProxyError: ProxyError, - httpcore.UnsupportedProtocol: UnsupportedProtocol, - httpcore.ProtocolError: ProtocolError, - httpcore.LocalProtocolError: LocalProtocolError, - httpcore.RemoteProtocolError: RemoteProtocolError, - } - - -@contextlib.contextmanager -def map_httpcore_exceptions() -> typing.Iterator[None]: - global HTTPCORE_EXC_MAP - if len(HTTPCORE_EXC_MAP) == 0: - HTTPCORE_EXC_MAP = _load_httpcore_exceptions() - try: - yield - except Exception as exc: - mapped_exc = None - - for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): - if not isinstance(exc, from_exc): - continue - # We want to map to the most specific exception we can find. - # Eg if `exc` is an `httpcore.ReadTimeout`, we want to map to - # `httpx.ReadTimeout`, not just `httpx.TimeoutException`. - if mapped_exc is None or issubclass(to_exc, mapped_exc): - mapped_exc = to_exc - - if mapped_exc is None: # pragma: no cover - raise - - message = str(exc) - raise mapped_exc(message) from exc - - -class ResponseStream(SyncByteStream): - def __init__(self, httpcore_stream: typing.Iterable[bytes]) -> None: - self._httpcore_stream = httpcore_stream - - def __iter__(self) -> typing.Iterator[bytes]: - with map_httpcore_exceptions(): - for part in self._httpcore_stream: - yield part - - def close(self) -> None: - if hasattr(self._httpcore_stream, "close"): - self._httpcore_stream.close() - - -class HTTPTransport(BaseTransport): - def __init__( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - proxy: ProxyTypes | None = None, - uds: str | None = None, - local_address: str | None = None, - retries: int = 0, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - import httpcore - - proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy - ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env) - - if proxy is None: - self._pool = httpcore.ConnectionPool( - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - uds=uds, - local_address=local_address, - retries=retries, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("http", "https"): - self._pool = httpcore.HTTPProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - proxy_headers=proxy.headers.raw, - ssl_context=ssl_context, - proxy_ssl_context=proxy.ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("socks5", "socks5h"): - try: - import socksio # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using SOCKS proxy, but the 'socksio' package is not installed. " - "Make sure to install httpx using `pip install httpx[socks]`." - ) from None - - self._pool = httpcore.SOCKSProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - ) - else: # pragma: no cover - raise ValueError( - "Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h'," - f" but got {proxy.url.scheme!r}." - ) - - def __enter__(self: T) -> T: # Use generics for subclass support. - self._pool.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - with map_httpcore_exceptions(): - self._pool.__exit__(exc_type, exc_value, traceback) - - def handle_request( - self, - request: Request, - ) -> Response: - assert isinstance(request.stream, SyncByteStream) - import httpcore - - req = httpcore.Request( - method=request.method, - url=httpcore.URL( - scheme=request.url.raw_scheme, - host=request.url.raw_host, - port=request.url.port, - target=request.url.raw_path, - ), - headers=request.headers.raw, - content=request.stream, - extensions=request.extensions, - ) - with map_httpcore_exceptions(): - resp = self._pool.handle_request(req) - - assert isinstance(resp.stream, typing.Iterable) - - return Response( - status_code=resp.status, - headers=resp.headers, - stream=ResponseStream(resp.stream), - extensions=resp.extensions, - ) - - def close(self) -> None: - self._pool.close() - - -class AsyncResponseStream(AsyncByteStream): - def __init__(self, httpcore_stream: typing.AsyncIterable[bytes]) -> None: - self._httpcore_stream = httpcore_stream - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - with map_httpcore_exceptions(): - async for part in self._httpcore_stream: - yield part - - async def aclose(self) -> None: - if hasattr(self._httpcore_stream, "aclose"): - await self._httpcore_stream.aclose() - - -class AsyncHTTPTransport(AsyncBaseTransport): - def __init__( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - proxy: ProxyTypes | None = None, - uds: str | None = None, - local_address: str | None = None, - retries: int = 0, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - import httpcore - - proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy - ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env) - - if proxy is None: - self._pool = httpcore.AsyncConnectionPool( - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - uds=uds, - local_address=local_address, - retries=retries, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("http", "https"): - self._pool = httpcore.AsyncHTTPProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - proxy_headers=proxy.headers.raw, - proxy_ssl_context=proxy.ssl_context, - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("socks5", "socks5h"): - try: - import socksio # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using SOCKS proxy, but the 'socksio' package is not installed. " - "Make sure to install httpx using `pip install httpx[socks]`." - ) from None - - self._pool = httpcore.AsyncSOCKSProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - ) - else: # pragma: no cover - raise ValueError( - "Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h'," - " but got {proxy.url.scheme!r}." - ) - - async def __aenter__(self: A) -> A: # Use generics for subclass support. - await self._pool.__aenter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - with map_httpcore_exceptions(): - await self._pool.__aexit__(exc_type, exc_value, traceback) - - async def handle_async_request( - self, - request: Request, - ) -> Response: - assert isinstance(request.stream, AsyncByteStream) - import httpcore - - req = httpcore.Request( - method=request.method, - url=httpcore.URL( - scheme=request.url.raw_scheme, - host=request.url.raw_host, - port=request.url.port, - target=request.url.raw_path, - ), - headers=request.headers.raw, - content=request.stream, - extensions=request.extensions, - ) - with map_httpcore_exceptions(): - resp = await self._pool.handle_async_request(req) - - assert isinstance(resp.stream, typing.AsyncIterable) - - return Response( - status_code=resp.status, - headers=resp.headers, - stream=AsyncResponseStream(resp.stream), - extensions=resp.extensions, - ) - - async def aclose(self) -> None: - await self._pool.aclose() diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/mock.py b/venv/lib/python3.10/site-packages/httpx/_transports/mock.py deleted file mode 100644 index 8c418f59e06cae43abdbb626ec21cafc7e8c6277..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_transports/mock.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations - -import typing - -from .._models import Request, Response -from .base import AsyncBaseTransport, BaseTransport - -SyncHandler = typing.Callable[[Request], Response] -AsyncHandler = typing.Callable[[Request], typing.Coroutine[None, None, Response]] - - -__all__ = ["MockTransport"] - - -class MockTransport(AsyncBaseTransport, BaseTransport): - def __init__(self, handler: SyncHandler | AsyncHandler) -> None: - self.handler = handler - - def handle_request( - self, - request: Request, - ) -> Response: - request.read() - response = self.handler(request) - if not isinstance(response, Response): # pragma: no cover - raise TypeError("Cannot use an async handler in a sync Client") - return response - - async def handle_async_request( - self, - request: Request, - ) -> Response: - await request.aread() - response = self.handler(request) - - # Allow handler to *optionally* be an `async` function. - # If it is, then the `response` variable need to be awaited to actually - # return the result. - - if not isinstance(response, Response): - response = await response - - return response diff --git a/venv/lib/python3.10/site-packages/httpx/_transports/wsgi.py b/venv/lib/python3.10/site-packages/httpx/_transports/wsgi.py deleted file mode 100644 index 8592ffe017a87367cc7578184540096a9682908d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_transports/wsgi.py +++ /dev/null @@ -1,149 +0,0 @@ -from __future__ import annotations - -import io -import itertools -import sys -import typing - -from .._models import Request, Response -from .._types import SyncByteStream -from .base import BaseTransport - -if typing.TYPE_CHECKING: - from _typeshed import OptExcInfo # pragma: no cover - from _typeshed.wsgi import WSGIApplication # pragma: no cover - -_T = typing.TypeVar("_T") - - -__all__ = ["WSGITransport"] - - -def _skip_leading_empty_chunks(body: typing.Iterable[_T]) -> typing.Iterable[_T]: - body = iter(body) - for chunk in body: - if chunk: - return itertools.chain([chunk], body) - return [] - - -class WSGIByteStream(SyncByteStream): - def __init__(self, result: typing.Iterable[bytes]) -> None: - self._close = getattr(result, "close", None) - self._result = _skip_leading_empty_chunks(result) - - def __iter__(self) -> typing.Iterator[bytes]: - for part in self._result: - yield part - - def close(self) -> None: - if self._close is not None: - self._close() - - -class WSGITransport(BaseTransport): - """ - A custom transport that handles sending requests directly to an WSGI app. - The simplest way to use this functionality is to use the `app` argument. - - ``` - client = httpx.Client(app=app) - ``` - - Alternatively, you can setup the transport instance explicitly. - This allows you to include any additional configuration arguments specific - to the WSGITransport class: - - ``` - transport = httpx.WSGITransport( - app=app, - script_name="/submount", - remote_addr="1.2.3.4" - ) - client = httpx.Client(transport=transport) - ``` - - Arguments: - - * `app` - The WSGI application. - * `raise_app_exceptions` - Boolean indicating if exceptions in the application - should be raised. Default to `True`. Can be set to `False` for use cases - such as testing the content of a client 500 response. - * `script_name` - The root path on which the WSGI application should be mounted. - * `remote_addr` - A string indicating the client IP of incoming requests. - ``` - """ - - def __init__( - self, - app: WSGIApplication, - raise_app_exceptions: bool = True, - script_name: str = "", - remote_addr: str = "127.0.0.1", - wsgi_errors: typing.TextIO | None = None, - ) -> None: - self.app = app - self.raise_app_exceptions = raise_app_exceptions - self.script_name = script_name - self.remote_addr = remote_addr - self.wsgi_errors = wsgi_errors - - def handle_request(self, request: Request) -> Response: - request.read() - wsgi_input = io.BytesIO(request.content) - - port = request.url.port or {"http": 80, "https": 443}[request.url.scheme] - environ = { - "wsgi.version": (1, 0), - "wsgi.url_scheme": request.url.scheme, - "wsgi.input": wsgi_input, - "wsgi.errors": self.wsgi_errors or sys.stderr, - "wsgi.multithread": True, - "wsgi.multiprocess": False, - "wsgi.run_once": False, - "REQUEST_METHOD": request.method, - "SCRIPT_NAME": self.script_name, - "PATH_INFO": request.url.path, - "QUERY_STRING": request.url.query.decode("ascii"), - "SERVER_NAME": request.url.host, - "SERVER_PORT": str(port), - "SERVER_PROTOCOL": "HTTP/1.1", - "REMOTE_ADDR": self.remote_addr, - } - for header_key, header_value in request.headers.raw: - key = header_key.decode("ascii").upper().replace("-", "_") - if key not in ("CONTENT_TYPE", "CONTENT_LENGTH"): - key = "HTTP_" + key - environ[key] = header_value.decode("ascii") - - seen_status = None - seen_response_headers = None - seen_exc_info = None - - def start_response( - status: str, - response_headers: list[tuple[str, str]], - exc_info: OptExcInfo | None = None, - ) -> typing.Callable[[bytes], typing.Any]: - nonlocal seen_status, seen_response_headers, seen_exc_info - seen_status = status - seen_response_headers = response_headers - seen_exc_info = exc_info - return lambda _: None - - result = self.app(environ, start_response) - - stream = WSGIByteStream(result) - - assert seen_status is not None - assert seen_response_headers is not None - if seen_exc_info and seen_exc_info[0] and self.raise_app_exceptions: - raise seen_exc_info[1] - - status_code = int(seen_status.split()[0]) - headers = [ - (key.encode("ascii"), value.encode("ascii")) - for key, value in seen_response_headers - ] - - return Response(status_code, headers=headers, stream=stream) diff --git a/venv/lib/python3.10/site-packages/httpx/_types.py b/venv/lib/python3.10/site-packages/httpx/_types.py deleted file mode 100644 index 704dfdffc8ba61eb913fa918072381e410b23c00..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_types.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -Type definitions for type checking purposes. -""" - -from http.cookiejar import CookieJar -from typing import ( - IO, - TYPE_CHECKING, - Any, - AsyncIterable, - AsyncIterator, - Callable, - Dict, - Iterable, - Iterator, - List, - Mapping, - Optional, - Sequence, - Tuple, - Union, -) - -if TYPE_CHECKING: # pragma: no cover - from ._auth import Auth # noqa: F401 - from ._config import Proxy, Timeout # noqa: F401 - from ._models import Cookies, Headers, Request # noqa: F401 - from ._urls import URL, QueryParams # noqa: F401 - - -PrimitiveData = Optional[Union[str, int, float, bool]] - -URLTypes = Union["URL", str] - -QueryParamTypes = Union[ - "QueryParams", - Mapping[str, Union[PrimitiveData, Sequence[PrimitiveData]]], - List[Tuple[str, PrimitiveData]], - Tuple[Tuple[str, PrimitiveData], ...], - str, - bytes, -] - -HeaderTypes = Union[ - "Headers", - Mapping[str, str], - Mapping[bytes, bytes], - Sequence[Tuple[str, str]], - Sequence[Tuple[bytes, bytes]], -] - -CookieTypes = Union["Cookies", CookieJar, Dict[str, str], List[Tuple[str, str]]] - -TimeoutTypes = Union[ - Optional[float], - Tuple[Optional[float], Optional[float], Optional[float], Optional[float]], - "Timeout", -] -ProxyTypes = Union["URL", str, "Proxy"] -CertTypes = Union[str, Tuple[str, str], Tuple[str, str, str]] - -AuthTypes = Union[ - Tuple[Union[str, bytes], Union[str, bytes]], - Callable[["Request"], "Request"], - "Auth", -] - -RequestContent = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] -ResponseContent = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] -ResponseExtensions = Mapping[str, Any] - -RequestData = Mapping[str, Any] - -FileContent = Union[IO[bytes], bytes, str] -FileTypes = Union[ - # file (or bytes) - FileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], FileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], FileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], -] -RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] - -RequestExtensions = Mapping[str, Any] - -__all__ = ["AsyncByteStream", "SyncByteStream"] - - -class SyncByteStream: - def __iter__(self) -> Iterator[bytes]: - raise NotImplementedError( - "The '__iter__' method must be implemented." - ) # pragma: no cover - yield b"" # pragma: no cover - - def close(self) -> None: - """ - Subclasses can override this method to release any network resources - after a request/response cycle is complete. - """ - - -class AsyncByteStream: - async def __aiter__(self) -> AsyncIterator[bytes]: - raise NotImplementedError( - "The '__aiter__' method must be implemented." - ) # pragma: no cover - yield b"" # pragma: no cover - - async def aclose(self) -> None: - pass diff --git a/venv/lib/python3.10/site-packages/httpx/_urlparse.py b/venv/lib/python3.10/site-packages/httpx/_urlparse.py deleted file mode 100644 index bf190fd560ee4fc8a11af371a15fc5f1dc284d34..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_urlparse.py +++ /dev/null @@ -1,527 +0,0 @@ -""" -An implementation of `urlparse` that provides URL validation and normalization -as described by RFC3986. - -We rely on this implementation rather than the one in Python's stdlib, because: - -* It provides more complete URL validation. -* It properly differentiates between an empty querystring and an absent querystring, - to distinguish URLs with a trailing '?'. -* It handles scheme, hostname, port, and path normalization. -* It supports IDNA hostnames, normalizing them to their encoded form. -* The API supports passing individual components, as well as the complete URL string. - -Previously we relied on the excellent `rfc3986` package to handle URL parsing and -validation, but this module provides a simpler alternative, with less indirection -required. -""" - -from __future__ import annotations - -import ipaddress -import re -import typing - -import idna - -from ._exceptions import InvalidURL - -MAX_URL_LENGTH = 65536 - -# https://datatracker.ietf.org/doc/html/rfc3986.html#section-2.3 -UNRESERVED_CHARACTERS = ( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" -) -SUB_DELIMS = "!$&'()*+,;=" - -PERCENT_ENCODED_REGEX = re.compile("%[A-Fa-f0-9]{2}") - -# https://url.spec.whatwg.org/#percent-encoded-bytes - -# The fragment percent-encode set is the C0 control percent-encode set -# and U+0020 SPACE, U+0022 ("), U+003C (<), U+003E (>), and U+0060 (`). -FRAG_SAFE = "".join( - [chr(i) for i in range(0x20, 0x7F) if i not in (0x20, 0x22, 0x3C, 0x3E, 0x60)] -) - -# The query percent-encode set is the C0 control percent-encode set -# and U+0020 SPACE, U+0022 ("), U+0023 (#), U+003C (<), and U+003E (>). -QUERY_SAFE = "".join( - [chr(i) for i in range(0x20, 0x7F) if i not in (0x20, 0x22, 0x23, 0x3C, 0x3E)] -) - -# The path percent-encode set is the query percent-encode set -# and U+003F (?), U+0060 (`), U+007B ({), and U+007D (}). -PATH_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i not in (0x20, 0x22, 0x23, 0x3C, 0x3E) + (0x3F, 0x60, 0x7B, 0x7D) - ] -) - -# The userinfo percent-encode set is the path percent-encode set -# and U+002F (/), U+003A (:), U+003B (;), U+003D (=), U+0040 (@), -# U+005B ([) to U+005E (^), inclusive, and U+007C (|). -USERNAME_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i - not in (0x20, 0x22, 0x23, 0x3C, 0x3E) - + (0x3F, 0x60, 0x7B, 0x7D) - + (0x2F, 0x3A, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) - ] -) -PASSWORD_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i - not in (0x20, 0x22, 0x23, 0x3C, 0x3E) - + (0x3F, 0x60, 0x7B, 0x7D) - + (0x2F, 0x3A, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) - ] -) -# Note... The terminology 'userinfo' percent-encode set in the WHATWG document -# is used for the username and password quoting. For the joint userinfo component -# we remove U+003A (:) from the safe set. -USERINFO_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i - not in (0x20, 0x22, 0x23, 0x3C, 0x3E) - + (0x3F, 0x60, 0x7B, 0x7D) - + (0x2F, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) - ] -) - - -# {scheme}: (optional) -# //{authority} (optional) -# {path} -# ?{query} (optional) -# #{fragment} (optional) -URL_REGEX = re.compile( - ( - r"(?:(?P{scheme}):)?" - r"(?://(?P{authority}))?" - r"(?P{path})" - r"(?:\?(?P{query}))?" - r"(?:#(?P{fragment}))?" - ).format( - scheme="([a-zA-Z][a-zA-Z0-9+.-]*)?", - authority="[^/?#]*", - path="[^?#]*", - query="[^#]*", - fragment=".*", - ) -) - -# {userinfo}@ (optional) -# {host} -# :{port} (optional) -AUTHORITY_REGEX = re.compile( - ( - r"(?:(?P{userinfo})@)?" r"(?P{host})" r":?(?P{port})?" - ).format( - userinfo=".*", # Any character sequence. - host="(\\[.*\\]|[^:@]*)", # Either any character sequence excluding ':' or '@', - # or an IPv6 address enclosed within square brackets. - port=".*", # Any character sequence. - ) -) - - -# If we call urlparse with an individual component, then we need to regex -# validate that component individually. -# Note that we're duplicating the same strings as above. Shock! Horror!! -COMPONENT_REGEX = { - "scheme": re.compile("([a-zA-Z][a-zA-Z0-9+.-]*)?"), - "authority": re.compile("[^/?#]*"), - "path": re.compile("[^?#]*"), - "query": re.compile("[^#]*"), - "fragment": re.compile(".*"), - "userinfo": re.compile("[^@]*"), - "host": re.compile("(\\[.*\\]|[^:]*)"), - "port": re.compile(".*"), -} - - -# We use these simple regexs as a first pass before handing off to -# the stdlib 'ipaddress' module for IP address validation. -IPv4_STYLE_HOSTNAME = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") -IPv6_STYLE_HOSTNAME = re.compile(r"^\[.*\]$") - - -class ParseResult(typing.NamedTuple): - scheme: str - userinfo: str - host: str - port: int | None - path: str - query: str | None - fragment: str | None - - @property - def authority(self) -> str: - return "".join( - [ - f"{self.userinfo}@" if self.userinfo else "", - f"[{self.host}]" if ":" in self.host else self.host, - f":{self.port}" if self.port is not None else "", - ] - ) - - @property - def netloc(self) -> str: - return "".join( - [ - f"[{self.host}]" if ":" in self.host else self.host, - f":{self.port}" if self.port is not None else "", - ] - ) - - def copy_with(self, **kwargs: str | None) -> ParseResult: - if not kwargs: - return self - - defaults = { - "scheme": self.scheme, - "authority": self.authority, - "path": self.path, - "query": self.query, - "fragment": self.fragment, - } - defaults.update(kwargs) - return urlparse("", **defaults) - - def __str__(self) -> str: - authority = self.authority - return "".join( - [ - f"{self.scheme}:" if self.scheme else "", - f"//{authority}" if authority else "", - self.path, - f"?{self.query}" if self.query is not None else "", - f"#{self.fragment}" if self.fragment is not None else "", - ] - ) - - -def urlparse(url: str = "", **kwargs: str | None) -> ParseResult: - # Initial basic checks on allowable URLs. - # --------------------------------------- - - # Hard limit the maximum allowable URL length. - if len(url) > MAX_URL_LENGTH: - raise InvalidURL("URL too long") - - # If a URL includes any ASCII control characters including \t, \r, \n, - # then treat it as invalid. - if any(char.isascii() and not char.isprintable() for char in url): - char = next(char for char in url if char.isascii() and not char.isprintable()) - idx = url.find(char) - error = ( - f"Invalid non-printable ASCII character in URL, {char!r} at position {idx}." - ) - raise InvalidURL(error) - - # Some keyword arguments require special handling. - # ------------------------------------------------ - - # Coerce "port" to a string, if it is provided as an integer. - if "port" in kwargs: - port = kwargs["port"] - kwargs["port"] = str(port) if isinstance(port, int) else port - - # Replace "netloc" with "host and "port". - if "netloc" in kwargs: - netloc = kwargs.pop("netloc") or "" - kwargs["host"], _, kwargs["port"] = netloc.partition(":") - - # Replace "username" and/or "password" with "userinfo". - if "username" in kwargs or "password" in kwargs: - username = quote(kwargs.pop("username", "") or "", safe=USERNAME_SAFE) - password = quote(kwargs.pop("password", "") or "", safe=PASSWORD_SAFE) - kwargs["userinfo"] = f"{username}:{password}" if password else username - - # Replace "raw_path" with "path" and "query". - if "raw_path" in kwargs: - raw_path = kwargs.pop("raw_path") or "" - kwargs["path"], seperator, kwargs["query"] = raw_path.partition("?") - if not seperator: - kwargs["query"] = None - - # Ensure that IPv6 "host" addresses are always escaped with "[...]". - if "host" in kwargs: - host = kwargs.get("host") or "" - if ":" in host and not (host.startswith("[") and host.endswith("]")): - kwargs["host"] = f"[{host}]" - - # If any keyword arguments are provided, ensure they are valid. - # ------------------------------------------------------------- - - for key, value in kwargs.items(): - if value is not None: - if len(value) > MAX_URL_LENGTH: - raise InvalidURL(f"URL component '{key}' too long") - - # If a component includes any ASCII control characters including \t, \r, \n, - # then treat it as invalid. - if any(char.isascii() and not char.isprintable() for char in value): - char = next( - char for char in value if char.isascii() and not char.isprintable() - ) - idx = value.find(char) - error = ( - f"Invalid non-printable ASCII character in URL {key} component, " - f"{char!r} at position {idx}." - ) - raise InvalidURL(error) - - # Ensure that keyword arguments match as a valid regex. - if not COMPONENT_REGEX[key].fullmatch(value): - raise InvalidURL(f"Invalid URL component '{key}'") - - # The URL_REGEX will always match, but may have empty components. - url_match = URL_REGEX.match(url) - assert url_match is not None - url_dict = url_match.groupdict() - - # * 'scheme', 'authority', and 'path' may be empty strings. - # * 'query' may be 'None', indicating no trailing "?" portion. - # Any string including the empty string, indicates a trailing "?". - # * 'fragment' may be 'None', indicating no trailing "#" portion. - # Any string including the empty string, indicates a trailing "#". - scheme = kwargs.get("scheme", url_dict["scheme"]) or "" - authority = kwargs.get("authority", url_dict["authority"]) or "" - path = kwargs.get("path", url_dict["path"]) or "" - query = kwargs.get("query", url_dict["query"]) - frag = kwargs.get("fragment", url_dict["fragment"]) - - # The AUTHORITY_REGEX will always match, but may have empty components. - authority_match = AUTHORITY_REGEX.match(authority) - assert authority_match is not None - authority_dict = authority_match.groupdict() - - # * 'userinfo' and 'host' may be empty strings. - # * 'port' may be 'None'. - userinfo = kwargs.get("userinfo", authority_dict["userinfo"]) or "" - host = kwargs.get("host", authority_dict["host"]) or "" - port = kwargs.get("port", authority_dict["port"]) - - # Normalize and validate each component. - # We end up with a parsed representation of the URL, - # with components that are plain ASCII bytestrings. - parsed_scheme: str = scheme.lower() - parsed_userinfo: str = quote(userinfo, safe=USERINFO_SAFE) - parsed_host: str = encode_host(host) - parsed_port: int | None = normalize_port(port, scheme) - - has_scheme = parsed_scheme != "" - has_authority = ( - parsed_userinfo != "" or parsed_host != "" or parsed_port is not None - ) - validate_path(path, has_scheme=has_scheme, has_authority=has_authority) - if has_scheme or has_authority: - path = normalize_path(path) - - parsed_path: str = quote(path, safe=PATH_SAFE) - parsed_query: str | None = None if query is None else quote(query, safe=QUERY_SAFE) - parsed_frag: str | None = None if frag is None else quote(frag, safe=FRAG_SAFE) - - # The parsed ASCII bytestrings are our canonical form. - # All properties of the URL are derived from these. - return ParseResult( - parsed_scheme, - parsed_userinfo, - parsed_host, - parsed_port, - parsed_path, - parsed_query, - parsed_frag, - ) - - -def encode_host(host: str) -> str: - if not host: - return "" - - elif IPv4_STYLE_HOSTNAME.match(host): - # Validate IPv4 hostnames like #.#.#.# - # - # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 - # - # IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet - try: - ipaddress.IPv4Address(host) - except ipaddress.AddressValueError: - raise InvalidURL(f"Invalid IPv4 address: {host!r}") - return host - - elif IPv6_STYLE_HOSTNAME.match(host): - # Validate IPv6 hostnames like [...] - # - # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 - # - # "A host identified by an Internet Protocol literal address, version 6 - # [RFC3513] or later, is distinguished by enclosing the IP literal - # within square brackets ("[" and "]"). This is the only place where - # square bracket characters are allowed in the URI syntax." - try: - ipaddress.IPv6Address(host[1:-1]) - except ipaddress.AddressValueError: - raise InvalidURL(f"Invalid IPv6 address: {host!r}") - return host[1:-1] - - elif host.isascii(): - # Regular ASCII hostnames - # - # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 - # - # reg-name = *( unreserved / pct-encoded / sub-delims ) - WHATWG_SAFE = '"`{}%|\\' - return quote(host.lower(), safe=SUB_DELIMS + WHATWG_SAFE) - - # IDNA hostnames - try: - return idna.encode(host.lower()).decode("ascii") - except idna.IDNAError: - raise InvalidURL(f"Invalid IDNA hostname: {host!r}") - - -def normalize_port(port: str | int | None, scheme: str) -> int | None: - # From https://tools.ietf.org/html/rfc3986#section-3.2.3 - # - # "A scheme may define a default port. For example, the "http" scheme - # defines a default port of "80", corresponding to its reserved TCP - # port number. The type of port designated by the port number (e.g., - # TCP, UDP, SCTP) is defined by the URI scheme. URI producers and - # normalizers should omit the port component and its ":" delimiter if - # port is empty or if its value would be the same as that of the - # scheme's default." - if port is None or port == "": - return None - - try: - port_as_int = int(port) - except ValueError: - raise InvalidURL(f"Invalid port: {port!r}") - - # See https://url.spec.whatwg.org/#url-miscellaneous - default_port = {"ftp": 21, "http": 80, "https": 443, "ws": 80, "wss": 443}.get( - scheme - ) - if port_as_int == default_port: - return None - return port_as_int - - -def validate_path(path: str, has_scheme: bool, has_authority: bool) -> None: - """ - Path validation rules that depend on if the URL contains - a scheme or authority component. - - See https://datatracker.ietf.org/doc/html/rfc3986.html#section-3.3 - """ - if has_authority: - # If a URI contains an authority component, then the path component - # must either be empty or begin with a slash ("/") character." - if path and not path.startswith("/"): - raise InvalidURL("For absolute URLs, path must be empty or begin with '/'") - - if not has_scheme and not has_authority: - # If a URI does not contain an authority component, then the path cannot begin - # with two slash characters ("//"). - if path.startswith("//"): - raise InvalidURL("Relative URLs cannot have a path starting with '//'") - - # In addition, a URI reference (Section 4.1) may be a relative-path reference, - # in which case the first path segment cannot contain a colon (":") character. - if path.startswith(":"): - raise InvalidURL("Relative URLs cannot have a path starting with ':'") - - -def normalize_path(path: str) -> str: - """ - Drop "." and ".." segments from a URL path. - - For example: - - normalize_path("/path/./to/somewhere/..") == "/path/to" - """ - # Fast return when no '.' characters in the path. - if "." not in path: - return path - - components = path.split("/") - - # Fast return when no '.' or '..' components in the path. - if "." not in components and ".." not in components: - return path - - # https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 - output: list[str] = [] - for component in components: - if component == ".": - pass - elif component == "..": - if output and output != [""]: - output.pop() - else: - output.append(component) - return "/".join(output) - - -def PERCENT(string: str) -> str: - return "".join([f"%{byte:02X}" for byte in string.encode("utf-8")]) - - -def percent_encoded(string: str, safe: str) -> str: - """ - Use percent-encoding to quote a string. - """ - NON_ESCAPED_CHARS = UNRESERVED_CHARACTERS + safe - - # Fast path for strings that don't need escaping. - if not string.rstrip(NON_ESCAPED_CHARS): - return string - - return "".join( - [char if char in NON_ESCAPED_CHARS else PERCENT(char) for char in string] - ) - - -def quote(string: str, safe: str) -> str: - """ - Use percent-encoding to quote a string, omitting existing '%xx' escape sequences. - - See: https://www.rfc-editor.org/rfc/rfc3986#section-2.1 - - * `string`: The string to be percent-escaped. - * `safe`: A string containing characters that may be treated as safe, and do not - need to be escaped. Unreserved characters are always treated as safe. - See: https://www.rfc-editor.org/rfc/rfc3986#section-2.3 - """ - parts = [] - current_position = 0 - for match in re.finditer(PERCENT_ENCODED_REGEX, string): - start_position, end_position = match.start(), match.end() - matched_text = match.group(0) - # Add any text up to the '%xx' escape sequence. - if start_position != current_position: - leading_text = string[current_position:start_position] - parts.append(percent_encoded(leading_text, safe=safe)) - - # Add the '%xx' escape sequence. - parts.append(matched_text) - current_position = end_position - - # Add any text after the final '%xx' escape sequence. - if current_position != len(string): - trailing_text = string[current_position:] - parts.append(percent_encoded(trailing_text, safe=safe)) - - return "".join(parts) diff --git a/venv/lib/python3.10/site-packages/httpx/_urls.py b/venv/lib/python3.10/site-packages/httpx/_urls.py deleted file mode 100644 index 147a8fa333acaf31618d37ba2896e3a5bf5e4d02..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_urls.py +++ /dev/null @@ -1,641 +0,0 @@ -from __future__ import annotations - -import typing -from urllib.parse import parse_qs, unquote, urlencode - -import idna - -from ._types import QueryParamTypes -from ._urlparse import urlparse -from ._utils import primitive_value_to_str - -__all__ = ["URL", "QueryParams"] - - -class URL: - """ - url = httpx.URL("HTTPS://jo%40email.com:a%20secret@müller.de:1234/pa%20th?search=ab#anchorlink") - - assert url.scheme == "https" - assert url.username == "jo@email.com" - assert url.password == "a secret" - assert url.userinfo == b"jo%40email.com:a%20secret" - assert url.host == "müller.de" - assert url.raw_host == b"xn--mller-kva.de" - assert url.port == 1234 - assert url.netloc == b"xn--mller-kva.de:1234" - assert url.path == "/pa th" - assert url.query == b"?search=ab" - assert url.raw_path == b"/pa%20th?search=ab" - assert url.fragment == "anchorlink" - - The components of a URL are broken down like this: - - https://jo%40email.com:a%20secret@müller.de:1234/pa%20th?search=ab#anchorlink - [scheme] [ username ] [password] [ host ][port][ path ] [ query ] [fragment] - [ userinfo ] [ netloc ][ raw_path ] - - Note that: - - * `url.scheme` is normalized to always be lowercased. - - * `url.host` is normalized to always be lowercased. Internationalized domain - names are represented in unicode, without IDNA encoding applied. For instance: - - url = httpx.URL("http://中国.icom.museum") - assert url.host == "中国.icom.museum" - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.host == "中国.icom.museum" - - * `url.raw_host` is normalized to always be lowercased, and is IDNA encoded. - - url = httpx.URL("http://中国.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - - * `url.port` is either None or an integer. URLs that include the default port for - "http", "https", "ws", "wss", and "ftp" schemes have their port - normalized to `None`. - - assert httpx.URL("http://example.com") == httpx.URL("http://example.com:80") - assert httpx.URL("http://example.com").port is None - assert httpx.URL("http://example.com:80").port is None - - * `url.userinfo` is raw bytes, without URL escaping. Usually you'll want to work - with `url.username` and `url.password` instead, which handle the URL escaping. - - * `url.raw_path` is raw bytes of both the path and query, without URL escaping. - This portion is used as the target when constructing HTTP requests. Usually you'll - want to work with `url.path` instead. - - * `url.query` is raw bytes, without URL escaping. A URL query string portion can - only be properly URL escaped when decoding the parameter names and values - themselves. - """ - - def __init__(self, url: URL | str = "", **kwargs: typing.Any) -> None: - if kwargs: - allowed = { - "scheme": str, - "username": str, - "password": str, - "userinfo": bytes, - "host": str, - "port": int, - "netloc": bytes, - "path": str, - "query": bytes, - "raw_path": bytes, - "fragment": str, - "params": object, - } - - # Perform type checking for all supported keyword arguments. - for key, value in kwargs.items(): - if key not in allowed: - message = f"{key!r} is an invalid keyword argument for URL()" - raise TypeError(message) - if value is not None and not isinstance(value, allowed[key]): - expected = allowed[key].__name__ - seen = type(value).__name__ - message = f"Argument {key!r} must be {expected} but got {seen}" - raise TypeError(message) - if isinstance(value, bytes): - kwargs[key] = value.decode("ascii") - - if "params" in kwargs: - # Replace any "params" keyword with the raw "query" instead. - # - # Ensure that empty params use `kwargs["query"] = None` rather - # than `kwargs["query"] = ""`, so that generated URLs do not - # include an empty trailing "?". - params = kwargs.pop("params") - kwargs["query"] = None if not params else str(QueryParams(params)) - - if isinstance(url, str): - self._uri_reference = urlparse(url, **kwargs) - elif isinstance(url, URL): - self._uri_reference = url._uri_reference.copy_with(**kwargs) - else: - raise TypeError( - "Invalid type for url. Expected str or httpx.URL," - f" got {type(url)}: {url!r}" - ) - - @property - def scheme(self) -> str: - """ - The URL scheme, such as "http", "https". - Always normalised to lowercase. - """ - return self._uri_reference.scheme - - @property - def raw_scheme(self) -> bytes: - """ - The raw bytes representation of the URL scheme, such as b"http", b"https". - Always normalised to lowercase. - """ - return self._uri_reference.scheme.encode("ascii") - - @property - def userinfo(self) -> bytes: - """ - The URL userinfo as a raw bytestring. - For example: b"jo%40email.com:a%20secret". - """ - return self._uri_reference.userinfo.encode("ascii") - - @property - def username(self) -> str: - """ - The URL username as a string, with URL decoding applied. - For example: "jo@email.com" - """ - userinfo = self._uri_reference.userinfo - return unquote(userinfo.partition(":")[0]) - - @property - def password(self) -> str: - """ - The URL password as a string, with URL decoding applied. - For example: "a secret" - """ - userinfo = self._uri_reference.userinfo - return unquote(userinfo.partition(":")[2]) - - @property - def host(self) -> str: - """ - The URL host as a string. - Always normalized to lowercase, with IDNA hosts decoded into unicode. - - Examples: - - url = httpx.URL("http://www.EXAMPLE.org") - assert url.host == "www.example.org" - - url = httpx.URL("http://中国.icom.museum") - assert url.host == "中国.icom.museum" - - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.host == "中国.icom.museum" - - url = httpx.URL("https://[::ffff:192.168.0.1]") - assert url.host == "::ffff:192.168.0.1" - """ - host: str = self._uri_reference.host - - if host.startswith("xn--"): - host = idna.decode(host) - - return host - - @property - def raw_host(self) -> bytes: - """ - The raw bytes representation of the URL host. - Always normalized to lowercase, and IDNA encoded. - - Examples: - - url = httpx.URL("http://www.EXAMPLE.org") - assert url.raw_host == b"www.example.org" - - url = httpx.URL("http://中国.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - - url = httpx.URL("https://[::ffff:192.168.0.1]") - assert url.raw_host == b"::ffff:192.168.0.1" - """ - return self._uri_reference.host.encode("ascii") - - @property - def port(self) -> int | None: - """ - The URL port as an integer. - - Note that the URL class performs port normalization as per the WHATWG spec. - Default ports for "http", "https", "ws", "wss", and "ftp" schemes are always - treated as `None`. - - For example: - - assert httpx.URL("http://www.example.com") == httpx.URL("http://www.example.com:80") - assert httpx.URL("http://www.example.com:80").port is None - """ - return self._uri_reference.port - - @property - def netloc(self) -> bytes: - """ - Either `` or `:` as bytes. - Always normalized to lowercase, and IDNA encoded. - - This property may be used for generating the value of a request - "Host" header. - """ - return self._uri_reference.netloc.encode("ascii") - - @property - def path(self) -> str: - """ - The URL path as a string. Excluding the query string, and URL decoded. - - For example: - - url = httpx.URL("https://example.com/pa%20th") - assert url.path == "/pa th" - """ - path = self._uri_reference.path or "/" - return unquote(path) - - @property - def query(self) -> bytes: - """ - The URL query string, as raw bytes, excluding the leading b"?". - - This is necessarily a bytewise interface, because we cannot - perform URL decoding of this representation until we've parsed - the keys and values into a QueryParams instance. - - For example: - - url = httpx.URL("https://example.com/?filter=some%20search%20terms") - assert url.query == b"filter=some%20search%20terms" - """ - query = self._uri_reference.query or "" - return query.encode("ascii") - - @property - def params(self) -> QueryParams: - """ - The URL query parameters, neatly parsed and packaged into an immutable - multidict representation. - """ - return QueryParams(self._uri_reference.query) - - @property - def raw_path(self) -> bytes: - """ - The complete URL path and query string as raw bytes. - Used as the target when constructing HTTP requests. - - For example: - - GET /users?search=some%20text HTTP/1.1 - Host: www.example.org - Connection: close - """ - path = self._uri_reference.path or "/" - if self._uri_reference.query is not None: - path += "?" + self._uri_reference.query - return path.encode("ascii") - - @property - def fragment(self) -> str: - """ - The URL fragments, as used in HTML anchors. - As a string, without the leading '#'. - """ - return unquote(self._uri_reference.fragment or "") - - @property - def is_absolute_url(self) -> bool: - """ - Return `True` for absolute URLs such as 'http://example.com/path', - and `False` for relative URLs such as '/path'. - """ - # We don't use `.is_absolute` from `rfc3986` because it treats - # URLs with a fragment portion as not absolute. - # What we actually care about is if the URL provides - # a scheme and hostname to which connections should be made. - return bool(self._uri_reference.scheme and self._uri_reference.host) - - @property - def is_relative_url(self) -> bool: - """ - Return `False` for absolute URLs such as 'http://example.com/path', - and `True` for relative URLs such as '/path'. - """ - return not self.is_absolute_url - - def copy_with(self, **kwargs: typing.Any) -> URL: - """ - Copy this URL, returning a new URL with some components altered. - Accepts the same set of parameters as the components that are made - available via properties on the `URL` class. - - For example: - - url = httpx.URL("https://www.example.com").copy_with( - username="jo@gmail.com", password="a secret" - ) - assert url == "https://jo%40email.com:a%20secret@www.example.com" - """ - return URL(self, **kwargs) - - def copy_set_param(self, key: str, value: typing.Any = None) -> URL: - return self.copy_with(params=self.params.set(key, value)) - - def copy_add_param(self, key: str, value: typing.Any = None) -> URL: - return self.copy_with(params=self.params.add(key, value)) - - def copy_remove_param(self, key: str) -> URL: - return self.copy_with(params=self.params.remove(key)) - - def copy_merge_params(self, params: QueryParamTypes) -> URL: - return self.copy_with(params=self.params.merge(params)) - - def join(self, url: URL | str) -> URL: - """ - Return an absolute URL, using this URL as the base. - - Eg. - - url = httpx.URL("https://www.example.com/test") - url = url.join("/new/path") - assert url == "https://www.example.com/new/path" - """ - from urllib.parse import urljoin - - return URL(urljoin(str(self), str(URL(url)))) - - def __hash__(self) -> int: - return hash(str(self)) - - def __eq__(self, other: typing.Any) -> bool: - return isinstance(other, (URL, str)) and str(self) == str(URL(other)) - - def __str__(self) -> str: - return str(self._uri_reference) - - def __repr__(self) -> str: - scheme, userinfo, host, port, path, query, fragment = self._uri_reference - - if ":" in userinfo: - # Mask any password component. - userinfo = f'{userinfo.split(":")[0]}:[secure]' - - authority = "".join( - [ - f"{userinfo}@" if userinfo else "", - f"[{host}]" if ":" in host else host, - f":{port}" if port is not None else "", - ] - ) - url = "".join( - [ - f"{self.scheme}:" if scheme else "", - f"//{authority}" if authority else "", - path, - f"?{query}" if query is not None else "", - f"#{fragment}" if fragment is not None else "", - ] - ) - - return f"{self.__class__.__name__}({url!r})" - - @property - def raw(self) -> tuple[bytes, bytes, int, bytes]: # pragma: nocover - import collections - import warnings - - warnings.warn("URL.raw is deprecated.") - RawURL = collections.namedtuple( - "RawURL", ["raw_scheme", "raw_host", "port", "raw_path"] - ) - return RawURL( - raw_scheme=self.raw_scheme, - raw_host=self.raw_host, - port=self.port, - raw_path=self.raw_path, - ) - - -class QueryParams(typing.Mapping[str, str]): - """ - URL query parameters, as a multi-dict. - """ - - def __init__(self, *args: QueryParamTypes | None, **kwargs: typing.Any) -> None: - assert len(args) < 2, "Too many arguments." - assert not (args and kwargs), "Cannot mix named and unnamed arguments." - - value = args[0] if args else kwargs - - if value is None or isinstance(value, (str, bytes)): - value = value.decode("ascii") if isinstance(value, bytes) else value - self._dict = parse_qs(value, keep_blank_values=True) - elif isinstance(value, QueryParams): - self._dict = {k: list(v) for k, v in value._dict.items()} - else: - dict_value: dict[typing.Any, list[typing.Any]] = {} - if isinstance(value, (list, tuple)): - # Convert list inputs like: - # [("a", "123"), ("a", "456"), ("b", "789")] - # To a dict representation, like: - # {"a": ["123", "456"], "b": ["789"]} - for item in value: - dict_value.setdefault(item[0], []).append(item[1]) - else: - # Convert dict inputs like: - # {"a": "123", "b": ["456", "789"]} - # To dict inputs where values are always lists, like: - # {"a": ["123"], "b": ["456", "789"]} - dict_value = { - k: list(v) if isinstance(v, (list, tuple)) else [v] - for k, v in value.items() - } - - # Ensure that keys and values are neatly coerced to strings. - # We coerce values `True` and `False` to JSON-like "true" and "false" - # representations, and coerce `None` values to the empty string. - self._dict = { - str(k): [primitive_value_to_str(item) for item in v] - for k, v in dict_value.items() - } - - def keys(self) -> typing.KeysView[str]: - """ - Return all the keys in the query params. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.keys()) == ["a", "b"] - """ - return self._dict.keys() - - def values(self) -> typing.ValuesView[str]: - """ - Return all the values in the query params. If a key occurs more than once - only the first item for that key is returned. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.values()) == ["123", "789"] - """ - return {k: v[0] for k, v in self._dict.items()}.values() - - def items(self) -> typing.ItemsView[str, str]: - """ - Return all items in the query params. If a key occurs more than once - only the first item for that key is returned. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.items()) == [("a", "123"), ("b", "789")] - """ - return {k: v[0] for k, v in self._dict.items()}.items() - - def multi_items(self) -> list[tuple[str, str]]: - """ - Return all items in the query params. Allow duplicate keys to occur. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.multi_items()) == [("a", "123"), ("a", "456"), ("b", "789")] - """ - multi_items: list[tuple[str, str]] = [] - for k, v in self._dict.items(): - multi_items.extend([(k, i) for i in v]) - return multi_items - - def get(self, key: typing.Any, default: typing.Any = None) -> typing.Any: - """ - Get a value from the query param for a given key. If the key occurs - more than once, then only the first value is returned. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert q.get("a") == "123" - """ - if key in self._dict: - return self._dict[str(key)][0] - return default - - def get_list(self, key: str) -> list[str]: - """ - Get all values from the query param for a given key. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert q.get_list("a") == ["123", "456"] - """ - return list(self._dict.get(str(key), [])) - - def set(self, key: str, value: typing.Any = None) -> QueryParams: - """ - Return a new QueryParams instance, setting the value of a key. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.set("a", "456") - assert q == httpx.QueryParams("a=456") - """ - q = QueryParams() - q._dict = dict(self._dict) - q._dict[str(key)] = [primitive_value_to_str(value)] - return q - - def add(self, key: str, value: typing.Any = None) -> QueryParams: - """ - Return a new QueryParams instance, setting or appending the value of a key. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.add("a", "456") - assert q == httpx.QueryParams("a=123&a=456") - """ - q = QueryParams() - q._dict = dict(self._dict) - q._dict[str(key)] = q.get_list(key) + [primitive_value_to_str(value)] - return q - - def remove(self, key: str) -> QueryParams: - """ - Return a new QueryParams instance, removing the value of a key. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.remove("a") - assert q == httpx.QueryParams("") - """ - q = QueryParams() - q._dict = dict(self._dict) - q._dict.pop(str(key), None) - return q - - def merge(self, params: QueryParamTypes | None = None) -> QueryParams: - """ - Return a new QueryParams instance, updated with. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.merge({"b": "456"}) - assert q == httpx.QueryParams("a=123&b=456") - - q = httpx.QueryParams("a=123") - q = q.merge({"a": "456", "b": "789"}) - assert q == httpx.QueryParams("a=456&b=789") - """ - q = QueryParams(params) - q._dict = {**self._dict, **q._dict} - return q - - def __getitem__(self, key: typing.Any) -> str: - return self._dict[key][0] - - def __contains__(self, key: typing.Any) -> bool: - return key in self._dict - - def __iter__(self) -> typing.Iterator[typing.Any]: - return iter(self.keys()) - - def __len__(self) -> int: - return len(self._dict) - - def __bool__(self) -> bool: - return bool(self._dict) - - def __hash__(self) -> int: - return hash(str(self)) - - def __eq__(self, other: typing.Any) -> bool: - if not isinstance(other, self.__class__): - return False - return sorted(self.multi_items()) == sorted(other.multi_items()) - - def __str__(self) -> str: - return urlencode(self.multi_items()) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - query_string = str(self) - return f"{class_name}({query_string!r})" - - def update(self, params: QueryParamTypes | None = None) -> None: - raise RuntimeError( - "QueryParams are immutable since 0.18.0. " - "Use `q = q.merge(...)` to create an updated copy." - ) - - def __setitem__(self, key: str, value: str) -> None: - raise RuntimeError( - "QueryParams are immutable since 0.18.0. " - "Use `q = q.set(key, value)` to create an updated copy." - ) diff --git a/venv/lib/python3.10/site-packages/httpx/_utils.py b/venv/lib/python3.10/site-packages/httpx/_utils.py deleted file mode 100644 index 7fe827da4d071b32ea6da44328629699d6fc88ce..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/httpx/_utils.py +++ /dev/null @@ -1,242 +0,0 @@ -from __future__ import annotations - -import ipaddress -import os -import re -import typing -from urllib.request import getproxies - -from ._types import PrimitiveData - -if typing.TYPE_CHECKING: # pragma: no cover - from ._urls import URL - - -def primitive_value_to_str(value: PrimitiveData) -> str: - """ - Coerce a primitive data type into a string value. - - Note that we prefer JSON-style 'true'/'false' for boolean values here. - """ - if value is True: - return "true" - elif value is False: - return "false" - elif value is None: - return "" - return str(value) - - -def get_environment_proxies() -> dict[str, str | None]: - """Gets proxy information from the environment""" - - # urllib.request.getproxies() falls back on System - # Registry and Config for proxies on Windows and macOS. - # We don't want to propagate non-HTTP proxies into - # our configuration such as 'TRAVIS_APT_PROXY'. - proxy_info = getproxies() - mounts: dict[str, str | None] = {} - - for scheme in ("http", "https", "all"): - if proxy_info.get(scheme): - hostname = proxy_info[scheme] - mounts[f"{scheme}://"] = ( - hostname if "://" in hostname else f"http://{hostname}" - ) - - no_proxy_hosts = [host.strip() for host in proxy_info.get("no", "").split(",")] - for hostname in no_proxy_hosts: - # See https://curl.haxx.se/libcurl/c/CURLOPT_NOPROXY.html for details - # on how names in `NO_PROXY` are handled. - if hostname == "*": - # If NO_PROXY=* is used or if "*" occurs as any one of the comma - # separated hostnames, then we should just bypass any information - # from HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and always ignore - # proxies. - return {} - elif hostname: - # NO_PROXY=.google.com is marked as "all://*.google.com, - # which disables "www.google.com" but not "google.com" - # NO_PROXY=google.com is marked as "all://*google.com, - # which disables "www.google.com" and "google.com". - # (But not "wwwgoogle.com") - # NO_PROXY can include domains, IPv6, IPv4 addresses and "localhost" - # NO_PROXY=example.com,::1,localhost,192.168.0.0/16 - if "://" in hostname: - mounts[hostname] = None - elif is_ipv4_hostname(hostname): - mounts[f"all://{hostname}"] = None - elif is_ipv6_hostname(hostname): - mounts[f"all://[{hostname}]"] = None - elif hostname.lower() == "localhost": - mounts[f"all://{hostname}"] = None - else: - mounts[f"all://*{hostname}"] = None - - return mounts - - -def to_bytes(value: str | bytes, encoding: str = "utf-8") -> bytes: - return value.encode(encoding) if isinstance(value, str) else value - - -def to_str(value: str | bytes, encoding: str = "utf-8") -> str: - return value if isinstance(value, str) else value.decode(encoding) - - -def to_bytes_or_str(value: str, match_type_of: typing.AnyStr) -> typing.AnyStr: - return value if isinstance(match_type_of, str) else value.encode() - - -def unquote(value: str) -> str: - return value[1:-1] if value[0] == value[-1] == '"' else value - - -def peek_filelike_length(stream: typing.Any) -> int | None: - """ - Given a file-like stream object, return its length in number of bytes - without reading it into memory. - """ - try: - # Is it an actual file? - fd = stream.fileno() - # Yup, seems to be an actual file. - length = os.fstat(fd).st_size - except (AttributeError, OSError): - # No... Maybe it's something that supports random access, like `io.BytesIO`? - try: - # Assuming so, go to end of stream to figure out its length, - # then put it back in place. - offset = stream.tell() - length = stream.seek(0, os.SEEK_END) - stream.seek(offset) - except (AttributeError, OSError): - # Not even that? Sorry, we're doomed... - return None - - return length - - -class URLPattern: - """ - A utility class currently used for making lookups against proxy keys... - - # Wildcard matching... - >>> pattern = URLPattern("all://") - >>> pattern.matches(httpx.URL("http://example.com")) - True - - # Witch scheme matching... - >>> pattern = URLPattern("https://") - >>> pattern.matches(httpx.URL("https://example.com")) - True - >>> pattern.matches(httpx.URL("http://example.com")) - False - - # With domain matching... - >>> pattern = URLPattern("https://example.com") - >>> pattern.matches(httpx.URL("https://example.com")) - True - >>> pattern.matches(httpx.URL("http://example.com")) - False - >>> pattern.matches(httpx.URL("https://other.com")) - False - - # Wildcard scheme, with domain matching... - >>> pattern = URLPattern("all://example.com") - >>> pattern.matches(httpx.URL("https://example.com")) - True - >>> pattern.matches(httpx.URL("http://example.com")) - True - >>> pattern.matches(httpx.URL("https://other.com")) - False - - # With port matching... - >>> pattern = URLPattern("https://example.com:1234") - >>> pattern.matches(httpx.URL("https://example.com:1234")) - True - >>> pattern.matches(httpx.URL("https://example.com")) - False - """ - - def __init__(self, pattern: str) -> None: - from ._urls import URL - - if pattern and ":" not in pattern: - raise ValueError( - f"Proxy keys should use proper URL forms rather " - f"than plain scheme strings. " - f'Instead of "{pattern}", use "{pattern}://"' - ) - - url = URL(pattern) - self.pattern = pattern - self.scheme = "" if url.scheme == "all" else url.scheme - self.host = "" if url.host == "*" else url.host - self.port = url.port - if not url.host or url.host == "*": - self.host_regex: typing.Pattern[str] | None = None - elif url.host.startswith("*."): - # *.example.com should match "www.example.com", but not "example.com" - domain = re.escape(url.host[2:]) - self.host_regex = re.compile(f"^.+\\.{domain}$") - elif url.host.startswith("*"): - # *example.com should match "www.example.com" and "example.com" - domain = re.escape(url.host[1:]) - self.host_regex = re.compile(f"^(.+\\.)?{domain}$") - else: - # example.com should match "example.com" but not "www.example.com" - domain = re.escape(url.host) - self.host_regex = re.compile(f"^{domain}$") - - def matches(self, other: URL) -> bool: - if self.scheme and self.scheme != other.scheme: - return False - if ( - self.host - and self.host_regex is not None - and not self.host_regex.match(other.host) - ): - return False - if self.port is not None and self.port != other.port: - return False - return True - - @property - def priority(self) -> tuple[int, int, int]: - """ - The priority allows URLPattern instances to be sortable, so that - we can match from most specific to least specific. - """ - # URLs with a port should take priority over URLs without a port. - port_priority = 0 if self.port is not None else 1 - # Longer hostnames should match first. - host_priority = -len(self.host) - # Longer schemes should match first. - scheme_priority = -len(self.scheme) - return (port_priority, host_priority, scheme_priority) - - def __hash__(self) -> int: - return hash(self.pattern) - - def __lt__(self, other: URLPattern) -> bool: - return self.priority < other.priority - - def __eq__(self, other: typing.Any) -> bool: - return isinstance(other, URLPattern) and self.pattern == other.pattern - - -def is_ipv4_hostname(hostname: str) -> bool: - try: - ipaddress.IPv4Address(hostname.split("/")[0]) - except Exception: - return False - return True - - -def is_ipv6_hostname(hostname: str) -> bool: - try: - ipaddress.IPv6Address(hostname.split("/")[0]) - except Exception: - return False - return True diff --git a/venv/lib/python3.10/site-packages/httpx/py.typed b/venv/lib/python3.10/site-packages/httpx/py.typed deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/INSTALLER b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e38a32041e49332e5e81c2d363dc418d68..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/METADATA b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/METADATA deleted file mode 100644 index be87a7773f1f3f691a655c24b2bfb226db66b024..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/METADATA +++ /dev/null @@ -1,320 +0,0 @@ -Metadata-Version: 2.4 -Name: huggingface_hub -Version: 1.4.1 -Summary: Client library to download and publish models, datasets and other repos on the huggingface.co hub -Home-page: https://github.com/huggingface/huggingface_hub -Author: Hugging Face, Inc. -Author-email: julien@huggingface.co -License: Apache -Keywords: model-hub machine-learning models natural-language-processing deep-learning pytorch pretrained-models -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Education -Classifier: Intended Audience :: Science/Research -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence -Requires-Python: >=3.9.0 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: filelock -Requires-Dist: fsspec>=2023.5.0 -Requires-Dist: hf-xet<2.0.0,>=1.2.0; platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "arm64" or platform_machine == "aarch64" -Requires-Dist: httpx<1,>=0.23.0 -Requires-Dist: packaging>=20.9 -Requires-Dist: pyyaml>=5.1 -Requires-Dist: shellingham -Requires-Dist: tqdm>=4.42.1 -Requires-Dist: typer-slim -Requires-Dist: typing-extensions>=4.1.0 -Provides-Extra: oauth -Requires-Dist: authlib>=1.3.2; extra == "oauth" -Requires-Dist: fastapi; extra == "oauth" -Requires-Dist: httpx; extra == "oauth" -Requires-Dist: itsdangerous; extra == "oauth" -Provides-Extra: torch -Requires-Dist: torch; extra == "torch" -Requires-Dist: safetensors[torch]; extra == "torch" -Provides-Extra: fastai -Requires-Dist: toml; extra == "fastai" -Requires-Dist: fastai>=2.4; extra == "fastai" -Requires-Dist: fastcore>=1.3.27; extra == "fastai" -Provides-Extra: hf-xet -Requires-Dist: hf-xet<2.0.0,>=1.2.0; extra == "hf-xet" -Provides-Extra: mcp -Requires-Dist: mcp>=1.8.0; extra == "mcp" -Provides-Extra: testing -Requires-Dist: authlib>=1.3.2; extra == "testing" -Requires-Dist: fastapi; extra == "testing" -Requires-Dist: httpx; extra == "testing" -Requires-Dist: itsdangerous; extra == "testing" -Requires-Dist: jedi; extra == "testing" -Requires-Dist: Jinja2; extra == "testing" -Requires-Dist: pytest>=8.4.2; extra == "testing" -Requires-Dist: pytest-cov; extra == "testing" -Requires-Dist: pytest-env; extra == "testing" -Requires-Dist: pytest-xdist; extra == "testing" -Requires-Dist: pytest-vcr; extra == "testing" -Requires-Dist: pytest-asyncio; extra == "testing" -Requires-Dist: pytest-rerunfailures<16.0; extra == "testing" -Requires-Dist: pytest-mock; extra == "testing" -Requires-Dist: urllib3<2.0; extra == "testing" -Requires-Dist: soundfile; extra == "testing" -Requires-Dist: Pillow; extra == "testing" -Requires-Dist: numpy; extra == "testing" -Requires-Dist: fastapi; extra == "testing" -Provides-Extra: typing -Requires-Dist: typing-extensions>=4.8.0; extra == "typing" -Requires-Dist: types-PyYAML; extra == "typing" -Requires-Dist: types-simplejson; extra == "typing" -Requires-Dist: types-toml; extra == "typing" -Requires-Dist: types-tqdm; extra == "typing" -Requires-Dist: types-urllib3; extra == "typing" -Provides-Extra: quality -Requires-Dist: ruff>=0.9.0; extra == "quality" -Requires-Dist: mypy==1.15.0; extra == "quality" -Requires-Dist: libcst>=1.4.0; extra == "quality" -Requires-Dist: ty; extra == "quality" -Provides-Extra: all -Requires-Dist: authlib>=1.3.2; extra == "all" -Requires-Dist: fastapi; extra == "all" -Requires-Dist: httpx; extra == "all" -Requires-Dist: itsdangerous; extra == "all" -Requires-Dist: jedi; extra == "all" -Requires-Dist: Jinja2; extra == "all" -Requires-Dist: pytest>=8.4.2; extra == "all" -Requires-Dist: pytest-cov; extra == "all" -Requires-Dist: pytest-env; extra == "all" -Requires-Dist: pytest-xdist; extra == "all" -Requires-Dist: pytest-vcr; extra == "all" -Requires-Dist: pytest-asyncio; extra == "all" -Requires-Dist: pytest-rerunfailures<16.0; extra == "all" -Requires-Dist: pytest-mock; extra == "all" -Requires-Dist: urllib3<2.0; extra == "all" -Requires-Dist: soundfile; extra == "all" -Requires-Dist: Pillow; extra == "all" -Requires-Dist: numpy; extra == "all" -Requires-Dist: fastapi; extra == "all" -Requires-Dist: ruff>=0.9.0; extra == "all" -Requires-Dist: mypy==1.15.0; extra == "all" -Requires-Dist: libcst>=1.4.0; extra == "all" -Requires-Dist: ty; extra == "all" -Requires-Dist: typing-extensions>=4.8.0; extra == "all" -Requires-Dist: types-PyYAML; extra == "all" -Requires-Dist: types-simplejson; extra == "all" -Requires-Dist: types-toml; extra == "all" -Requires-Dist: types-tqdm; extra == "all" -Requires-Dist: types-urllib3; extra == "all" -Provides-Extra: dev -Requires-Dist: authlib>=1.3.2; extra == "dev" -Requires-Dist: fastapi; extra == "dev" -Requires-Dist: httpx; extra == "dev" -Requires-Dist: itsdangerous; extra == "dev" -Requires-Dist: jedi; extra == "dev" -Requires-Dist: Jinja2; extra == "dev" -Requires-Dist: pytest>=8.4.2; extra == "dev" -Requires-Dist: pytest-cov; extra == "dev" -Requires-Dist: pytest-env; extra == "dev" -Requires-Dist: pytest-xdist; extra == "dev" -Requires-Dist: pytest-vcr; extra == "dev" -Requires-Dist: pytest-asyncio; extra == "dev" -Requires-Dist: pytest-rerunfailures<16.0; extra == "dev" -Requires-Dist: pytest-mock; extra == "dev" -Requires-Dist: urllib3<2.0; extra == "dev" -Requires-Dist: soundfile; extra == "dev" -Requires-Dist: Pillow; extra == "dev" -Requires-Dist: numpy; extra == "dev" -Requires-Dist: fastapi; extra == "dev" -Requires-Dist: ruff>=0.9.0; extra == "dev" -Requires-Dist: mypy==1.15.0; extra == "dev" -Requires-Dist: libcst>=1.4.0; extra == "dev" -Requires-Dist: ty; extra == "dev" -Requires-Dist: typing-extensions>=4.8.0; extra == "dev" -Requires-Dist: types-PyYAML; extra == "dev" -Requires-Dist: types-simplejson; extra == "dev" -Requires-Dist: types-toml; extra == "dev" -Requires-Dist: types-tqdm; extra == "dev" -Requires-Dist: types-urllib3; extra == "dev" -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: description-content-type -Dynamic: home-page -Dynamic: keywords -Dynamic: license -Dynamic: license-file -Dynamic: provides-extra -Dynamic: requires-dist -Dynamic: requires-python -Dynamic: summary - -

- - - - huggingface_hub library logo - -
-
-

- -

- The official Python client for the Huggingface Hub. -

- -

- Documentation - GitHub release - PyPi version - PyPI - Downloads - Code coverage -

- -

-

- English | - Deutsch | - Français | - हिंदी | - 한국어 | - 中文 (简体) -

-

- ---- - -**Documentation**: https://hf.co/docs/huggingface_hub - -**Source Code**: https://github.com/huggingface/huggingface_hub - ---- - -## Welcome to the huggingface_hub library - -The `huggingface_hub` library allows you to interact with the [Hugging Face Hub](https://huggingface.co/), a platform democratizing open-source Machine Learning for creators and collaborators. Discover pre-trained models and datasets for your projects or play with the thousands of machine learning apps hosted on the Hub. You can also create and share your own models, datasets and demos with the community. The `huggingface_hub` library provides a simple way to do all these things with Python. - -## Key features - -- [Download files](https://huggingface.co/docs/huggingface_hub/en/guides/download) from the Hub. -- [Upload files](https://huggingface.co/docs/huggingface_hub/en/guides/upload) to the Hub. -- [Manage your repositories](https://huggingface.co/docs/huggingface_hub/en/guides/repository). -- [Run Inference](https://huggingface.co/docs/huggingface_hub/en/guides/inference) on deployed models. -- [Search](https://huggingface.co/docs/huggingface_hub/en/guides/search) for models, datasets and Spaces. -- [Share Model Cards](https://huggingface.co/docs/huggingface_hub/en/guides/model-cards) to document your models. -- [Engage with the community](https://huggingface.co/docs/huggingface_hub/en/guides/community) through PRs and comments. - -## Installation - -Install the `huggingface_hub` package with [pip](https://pypi.org/project/huggingface-hub/): - -```bash -pip install huggingface_hub -``` - -If you prefer, you can also install it with [conda](https://huggingface.co/docs/huggingface_hub/en/installation#install-with-conda). - -In order to keep the package minimal by default, `huggingface_hub` comes with optional dependencies useful for some use cases. For example, if you want to use the MCP module, run: - -```bash -pip install "huggingface_hub[mcp]" -``` - -To learn more installation and optional dependencies, check out the [installation guide](https://huggingface.co/docs/huggingface_hub/en/installation). - -## Quick start - -### Download files - -Download a single file - -```py -from huggingface_hub import hf_hub_download - -hf_hub_download(repo_id="tiiuae/falcon-7b-instruct", filename="config.json") -``` - -Or an entire repository - -```py -from huggingface_hub import snapshot_download - -snapshot_download("stabilityai/stable-diffusion-2-1") -``` - -Files will be downloaded in a local cache folder. More details in [this guide](https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache). - -### Login - -The Hugging Face Hub uses tokens to authenticate applications (see [docs](https://huggingface.co/docs/hub/security-tokens)). To log in your machine, run the following CLI: - -```bash -hf auth login -# or using an environment variable -hf auth login --token $HUGGINGFACE_TOKEN -``` - -### Create a repository - -```py -from huggingface_hub import create_repo - -create_repo(repo_id="super-cool-model") -``` - -### Upload files - -Upload a single file - -```py -from huggingface_hub import upload_file - -upload_file( - path_or_fileobj="/home/lysandre/dummy-test/README.md", - path_in_repo="README.md", - repo_id="lysandre/test-model", -) -``` - -Or an entire folder - -```py -from huggingface_hub import upload_folder - -upload_folder( - folder_path="/path/to/local/space", - repo_id="username/my-cool-space", - repo_type="space", -) -``` - -For details in the [upload guide](https://huggingface.co/docs/huggingface_hub/en/guides/upload). - -## Integrating to the Hub. - -We're partnering with cool open source ML libraries to provide free model hosting and versioning. You can find the existing integrations [here](https://huggingface.co/docs/hub/libraries). - -The advantages are: - -- Free model or dataset hosting for libraries and their users. -- Built-in file versioning, even with very large files, thanks to a git-based approach. -- In-browser widgets to play with the uploaded models. -- Anyone can upload a new model for your library, they just need to add the corresponding tag for the model to be discoverable. -- Fast downloads! We use Cloudfront (a CDN) to geo-replicate downloads so they're blazing fast from anywhere on the globe. -- Usage stats and more features to come. - -If you would like to integrate your library, feel free to open an issue to begin the discussion. We wrote a [step-by-step guide](https://huggingface.co/docs/hub/adding-a-library) with ❤️ showing how to do this integration. - -## Contributions (feature requests, bugs, etc.) are super welcome 💙💚💛💜🧡❤️ - -Everyone is welcome to contribute, and we value everybody's contribution. Code is not the only way to help the community. -Answering questions, helping others, reaching out and improving the documentations are immensely valuable to the community. -We wrote a [contribution guide](https://github.com/huggingface/huggingface_hub/blob/main/CONTRIBUTING.md) to summarize -how to get started to contribute to this repository. diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/RECORD b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/RECORD deleted file mode 100644 index d955d4ec57c61008bbb9d42303661eedb6c7909d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/RECORD +++ /dev/null @@ -1,327 +0,0 @@ -../../../bin/hf,sha256=lzsDunMsRKlmFMlNVF1Cl6RDnOqDUV0-rOUdCABXHo0,386 -../../../bin/tiny-agents,sha256=rXAtpBZz-92JVzOAEhBAQ-uYGA0qhy6c_iknBuzLQj4,396 -huggingface_hub-1.4.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -huggingface_hub-1.4.1.dist-info/METADATA,sha256=ndkkQuwrvhLbrfnhtrIW9fxQfxYHlHvw3sRnAslqJ14,13853 -huggingface_hub-1.4.1.dist-info/RECORD,, -huggingface_hub-1.4.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -huggingface_hub-1.4.1.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91 -huggingface_hub-1.4.1.dist-info/entry_points.txt,sha256=j3KnOggx2dIP7NUkPyYgXdRnLxd94aHmqJ8J6tEZwY8,154 -huggingface_hub-1.4.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357 -huggingface_hub-1.4.1.dist-info/top_level.txt,sha256=8KzlQJAY4miUvjAssOAJodqKOw3harNzuiwGQ9qLSSk,16 -huggingface_hub/__init__.py,sha256=BFERnrZJkEPSU67qHT42XnEWPKtJlMrZAiV_mz1gKoQ,54930 -huggingface_hub/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/__pycache__/_commit_api.cpython-310.pyc,, -huggingface_hub/__pycache__/_commit_scheduler.cpython-310.pyc,, -huggingface_hub/__pycache__/_eval_results.cpython-310.pyc,, -huggingface_hub/__pycache__/_inference_endpoints.cpython-310.pyc,, -huggingface_hub/__pycache__/_jobs_api.cpython-310.pyc,, -huggingface_hub/__pycache__/_local_folder.cpython-310.pyc,, -huggingface_hub/__pycache__/_login.cpython-310.pyc,, -huggingface_hub/__pycache__/_oauth.cpython-310.pyc,, -huggingface_hub/__pycache__/_snapshot_download.cpython-310.pyc,, -huggingface_hub/__pycache__/_space_api.cpython-310.pyc,, -huggingface_hub/__pycache__/_tensorboard_logger.cpython-310.pyc,, -huggingface_hub/__pycache__/_upload_large_folder.cpython-310.pyc,, -huggingface_hub/__pycache__/_webhooks_payload.cpython-310.pyc,, -huggingface_hub/__pycache__/_webhooks_server.cpython-310.pyc,, -huggingface_hub/__pycache__/community.cpython-310.pyc,, -huggingface_hub/__pycache__/constants.cpython-310.pyc,, -huggingface_hub/__pycache__/dataclasses.cpython-310.pyc,, -huggingface_hub/__pycache__/errors.cpython-310.pyc,, -huggingface_hub/__pycache__/fastai_utils.cpython-310.pyc,, -huggingface_hub/__pycache__/file_download.cpython-310.pyc,, -huggingface_hub/__pycache__/hf_api.cpython-310.pyc,, -huggingface_hub/__pycache__/hf_file_system.cpython-310.pyc,, -huggingface_hub/__pycache__/hub_mixin.cpython-310.pyc,, -huggingface_hub/__pycache__/lfs.cpython-310.pyc,, -huggingface_hub/__pycache__/repocard.cpython-310.pyc,, -huggingface_hub/__pycache__/repocard_data.cpython-310.pyc,, -huggingface_hub/_commit_api.py,sha256=tc1vhwKwIzFZefUjQOGTdlEL0bFla2fW_dW76YxfKKs,40651 -huggingface_hub/_commit_scheduler.py,sha256=tqcdWVGJRIxGQtkFHs_AgBdN9ztUjOQSuAhfMAr1ieM,14751 -huggingface_hub/_eval_results.py,sha256=aXu75SmH2Jz-nY3S-dlrIdHuYrFqnG1i-BEkuAWA6o8,8160 -huggingface_hub/_inference_endpoints.py,sha256=UHWmeZdmwyHRDkfpChvYpLL-onwjNubjzhR9xZEmDqY,17722 -huggingface_hub/_jobs_api.py,sha256=4TnBy5pT4dfEsItzHB8AfPTCmHigoeWxbU0F4V3aBks,14032 -huggingface_hub/_local_folder.py,sha256=RdAqqGVTbzD2Bt6GFTxxBtrRyPAc7h9N5jYzByvP5IM,17497 -huggingface_hub/_login.py,sha256=OE_a7aEFWHZdrEteTZb2Ub5uRWzHRDZIf99_uci1ztY,19197 -huggingface_hub/_oauth.py,sha256=OU9t2Nc64dojA-z2g5XBHC4yqgzUkQXY64fYNWJTFMY,18694 -huggingface_hub/_snapshot_download.py,sha256=YQnl_fp3UiqMJf1Z-HYNHgiwm4QOeChQduQgXomiWA8,20595 -huggingface_hub/_space_api.py,sha256=2c7ainFpm2fI037AjHWuYghyOmUtLMwRK87ZCg77CLk,5468 -huggingface_hub/_tensorboard_logger.py,sha256=3TocVxxSIioqxOkI6p1N4plnWfAizfdU456V0-K10Bs,8414 -huggingface_hub/_upload_large_folder.py,sha256=zJa-25J7-Bwof1wHQ-zVGbBe2xmmuAL1qOSQI_VyR8U,30860 -huggingface_hub/_webhooks_payload.py,sha256=qCZjBa5dhssg_O0yzgzxPyMpwAxLG96I4qen_HIk0Qc,3611 -huggingface_hub/_webhooks_server.py,sha256=-trDDzwsFHuE0IIwxWJLtfq9D35k8AVas-UAMSn3qxc,15668 -huggingface_hub/cli/__init__.py,sha256=A4zmzuHD2OHjQ5zmdfcnsj0JeCzHVPtpzh-wCjInugA,606 -huggingface_hub/cli/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/_cli_utils.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/_errors.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/auth.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/cache.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/collections.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/datasets.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/download.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/hf.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/inference_endpoints.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/jobs.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/lfs.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/models.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/papers.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/repo.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/repo_files.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/skills.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/spaces.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/system.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/upload.cpython-310.pyc,, -huggingface_hub/cli/__pycache__/upload_large_folder.cpython-310.pyc,, -huggingface_hub/cli/_cli_utils.py,sha256=a2fYChUUFhD464SSHBNbgUf5u4VaYVPfkByoJxeFeH0,16950 -huggingface_hub/cli/_errors.py,sha256=j_qlkP3IMKbIL2RFnPLn9RL8xGS5UlHUbk3AEhZQ2gU,1713 -huggingface_hub/cli/auth.py,sha256=gOr1n8iqWrpqcK1aFNA69o3lnhUYaKetFBX9z0EdXbY,4676 -huggingface_hub/cli/cache.py,sha256=AFeProbR4Dwfqge6eY768MVuZQ8CVFQOp3jqJQpvSBc,27992 -huggingface_hub/cli/collections.py,sha256=v063dnrBS4gXRxLvaJ5qJ-xtigEL88w1MetAmv7KuAA,11127 -huggingface_hub/cli/datasets.py,sha256=T7ISV5_ENYPuwiBcPgIyb0VpeYoV4YdlYVs0n9snitY,3851 -huggingface_hub/cli/download.py,sha256=6Mw0rx9RHHnQXcEkVo2jFw4pk-__OKA3tZQXwRJwonw,6866 -huggingface_hub/cli/hf.py,sha256=DS6G_Tb6T0oeKMBo1i2ihBipsnk_7MFaiTlBaUpjWlI,3671 -huggingface_hub/cli/inference_endpoints.py,sha256=XEE2Wo_vjbUPRrNvxM6PtFo0sL8kJ_kRwdP4QWK-5c0,14500 -huggingface_hub/cli/jobs.py,sha256=cthtTY-mbCw-vtIig3LZnxNSswWsD0uCk4Qq7TbzzL0,35778 -huggingface_hub/cli/lfs.py,sha256=QLCYt2wtqrgCj42E9Nsm12X87ekKpxOia2ElBt0cmV4,5888 -huggingface_hub/cli/models.py,sha256=NijXVDO-ygIVx60TCqFqrCEnRMG6Tr6GC8A_5TdVzGE,3775 -huggingface_hub/cli/papers.py,sha256=clsIQCvpG1QkE1kgS72kP0Vt1Zhyu2vu-c0yknMVJvc,2646 -huggingface_hub/cli/repo.py,sha256=PNotI4ss6q1k4c-WpE6AVpDzPQBIS-LFjV-OMnzW7uo,10186 -huggingface_hub/cli/repo_files.py,sha256=fBLUK_uZ7S5PPXBlBIazI47g76BT9dRpVv1IZ3l8m5g,3026 -huggingface_hub/cli/skills.py,sha256=VfSg61AGuLwGpOzc-5O2TB5I8949aMqJEpJbbp5dovQ,6628 -huggingface_hub/cli/spaces.py,sha256=dDhuD73jdWCE1PHYY8o4my-i_0jgad9Y95xlsrmQ-XA,3752 -huggingface_hub/cli/system.py,sha256=RNEJRtrz3bt2r3-nY6XCgd46lb9-XWMgRt-lvMqRxN4,968 -huggingface_hub/cli/upload.py,sha256=dVUXk6X7bUxiIcLzMdnD88fdsYfHMz8IojqGsFQyj_A,11808 -huggingface_hub/cli/upload_large_folder.py,sha256=BS2XBOqTBjehc95SmBx9740rckHe8KL5YBBpyNfPJMc,4695 -huggingface_hub/community.py,sha256=FACeqlP7OgR2vLLJ0IN4cfglBiEGbyTafJ0cXfsjgnQ,12359 -huggingface_hub/constants.py,sha256=1xGvNmo7j_xkO3FoMv1rSA-EzgcgmMOwxv9E49_oeYM,10447 -huggingface_hub/dataclasses.py,sha256=xqfbimPAkQMffkhMoQbwrFAZBmBa_e6Ca3ensI1cIKA,23220 -huggingface_hub/errors.py,sha256=2-dpiLcLp5CF10wnJf52AO2XNQyRThHAaPiPQhu-IH4,12117 -huggingface_hub/fastai_utils.py,sha256=0joRPBUccjFALLCfhQLyD_K8qxGvQiLThKJClwej_JQ,16657 -huggingface_hub/file_download.py,sha256=JYEcRks51Gu-yN7RH6-1BaYN6AewigbuMAhLJ_5oj2w,83209 -huggingface_hub/hf_api.py,sha256=8NxKZJTnFIfZG-XIj58OOHYT5fZ6PJXESuYph5_chMY,506100 -huggingface_hub/hf_file_system.py,sha256=KDCRMXZoM6T8ZK1fecJIKkWhBFR0NRmvz_Jp-9O4rTw,54465 -huggingface_hub/hub_mixin.py,sha256=9VkPWMmxKr2PhyeGiaHxiUgs65DOhPCZQT_ZfOkaUhE,37092 -huggingface_hub/inference/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -huggingface_hub/inference/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/inference/__pycache__/_client.cpython-310.pyc,, -huggingface_hub/inference/__pycache__/_common.cpython-310.pyc,, -huggingface_hub/inference/_client.py,sha256=eZ7wni_Wz6bEE3ddKfmnkfEZmPs4gQNhyJoKOeysyFQ,158769 -huggingface_hub/inference/_common.py,sha256=GrQXvwwQsG2Ow2tpjlp1WdRN-AvQYJlzW0eeTfSOJ64,15074 -huggingface_hub/inference/_generated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -huggingface_hub/inference/_generated/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/inference/_generated/__pycache__/_async_client.cpython-310.pyc,, -huggingface_hub/inference/_generated/_async_client.py,sha256=sEDZekjPYbwNyyyO9ThsPYRG8G9P5Gn60Cc1eh8W1k0,161979 -huggingface_hub/inference/_generated/types/__init__.py,sha256=e625ENOmTUM4uUL1eAlsZOK7CovNoGBDH-TxSNQhaC4,6869 -huggingface_hub/inference/_generated/types/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/audio_classification.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/audio_to_audio.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/automatic_speech_recognition.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/base.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/chat_completion.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/depth_estimation.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/document_question_answering.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/feature_extraction.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/fill_mask.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/image_classification.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/image_segmentation.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/image_text_to_image.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/image_text_to_video.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/image_to_image.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/image_to_text.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/image_to_video.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/object_detection.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/question_answering.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/sentence_similarity.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/summarization.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/table_question_answering.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/text2text_generation.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/text_classification.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/text_generation.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/text_to_audio.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/text_to_image.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/text_to_speech.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/text_to_video.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/token_classification.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/translation.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/video_classification.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/visual_question_answering.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/zero_shot_classification.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/zero_shot_image_classification.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/__pycache__/zero_shot_object_detection.cpython-310.pyc,, -huggingface_hub/inference/_generated/types/audio_classification.py,sha256=Jg3mzfGhCSH6CfvVvgJSiFpkz6v4nNA0G4LJXacEgNc,1573 -huggingface_hub/inference/_generated/types/audio_to_audio.py,sha256=2Ep4WkePL7oJwcp5nRJqApwviumGHbft9HhXE9XLHj4,891 -huggingface_hub/inference/_generated/types/automatic_speech_recognition.py,sha256=FyViZkZqd0oo7Raqo48HESMAXHSnJap9HRWsKCi8Xz4,5509 -huggingface_hub/inference/_generated/types/base.py,sha256=3a2mWvQvMHszIZVzN4FNaYZdz_VsrTfw4jgeM4VwJXM,6970 -huggingface_hub/inference/_generated/types/chat_completion.py,sha256=3-pAyko3ozXSsvE_nFl4wtALf3z5DVQSLjtAD-2tUe4,11242 -huggingface_hub/inference/_generated/types/depth_estimation.py,sha256=c7IA81gZp5xIHol-7wlvy8V8UE--O1XF9rahauLVuoY,923 -huggingface_hub/inference/_generated/types/document_question_answering.py,sha256=aJ_dC3pVLTHombqX3UwIFhKN_mFzpw4m89sfB2J488E,3196 -huggingface_hub/inference/_generated/types/feature_extraction.py,sha256=xlo6LffaPlvickke537wAbTwbvjao82gnyWeUl1-WVs,1531 -huggingface_hub/inference/_generated/types/fill_mask.py,sha256=E-dU2bmHlso1cei_ju_LQtYVvDZEqAM1-walZkMPa74,1702 -huggingface_hub/inference/_generated/types/image_classification.py,sha256=A-Y024o8723_n8mGVos4TwdAkVL62McGeL1iIo4VzNs,1585 -huggingface_hub/inference/_generated/types/image_segmentation.py,sha256=vrkI4SuP1Iq_iLXc-2pQhYY3SHN4gzvFBoZqbUHxU7o,1950 -huggingface_hub/inference/_generated/types/image_text_to_image.py,sha256=MGEUbCi6p78OOuPPGrwxcitdbYFPN2JdfiA73d3MM-s,2619 -huggingface_hub/inference/_generated/types/image_text_to_video.py,sha256=1B3PZq3PCsoOz10Et_fOD7dPTvZQEPq3cZoFWX7_43I,2487 -huggingface_hub/inference/_generated/types/image_to_image.py,sha256=snvGbmCdqchxGef25MceD7LSKAmVkIgnoX5t71rdlAQ,2290 -huggingface_hub/inference/_generated/types/image_to_text.py,sha256=OaFEBAfgT-fOVzJ7xVermGf7VODhrc9-Jg38WrM7-2o,4810 -huggingface_hub/inference/_generated/types/image_to_video.py,sha256=bC-L_cNsDhk4s_IdSiprJ9d1NeMGePLcUp7UPpco21w,2240 -huggingface_hub/inference/_generated/types/object_detection.py,sha256=VuFlb1281qTXoSgJDmquGz-VNfEZLo2H0Rh_F6MF6ts,2000 -huggingface_hub/inference/_generated/types/question_answering.py,sha256=zw38a9_9l2k1ifYZefjkioqZ4asfSRM9M4nU3gSCmAQ,2898 -huggingface_hub/inference/_generated/types/sentence_similarity.py,sha256=5mDdTop4w6CpS-SulA03UVq5lBbzHuNMe8IQsTmAUPQ,1040 -huggingface_hub/inference/_generated/types/summarization.py,sha256=eMJvNJmxdImVXLLMADmyDeB1YhJbN3Qd_fC6lPB7mTM,1481 -huggingface_hub/inference/_generated/types/table_question_answering.py,sha256=SbgRCeEopJ0ig0U-q-Ft58kzD4aKfn1Dzu46r1g5z28,2281 -huggingface_hub/inference/_generated/types/text2text_generation.py,sha256=S9as2uJKqCmRht_dFGws-KwQwEq1hD6w3gSLiGTMERI,1603 -huggingface_hub/inference/_generated/types/text_classification.py,sha256=FarAjygLEfPofLfKeabzJ7PKEBItlHGoUNUOzyLRpL4,1445 -huggingface_hub/inference/_generated/types/text_generation.py,sha256=g9pLc5XrWc1Ir0nmQ4xTa4ZauKHIJ9Pr7yM1FmZkX0Y,5916 -huggingface_hub/inference/_generated/types/text_to_audio.py,sha256=1HR9Q6s9MXqtKGTvHPLGVMum5-eg7O-Pgv6Nd0v8_HU,4741 -huggingface_hub/inference/_generated/types/text_to_image.py,sha256=sGGi1Fa0n5Pmd6G3I-F2SBJcJ1M7Gmqnng6sfi0AVzs,1903 -huggingface_hub/inference/_generated/types/text_to_speech.py,sha256=ROFuR32ijROCeqbv81Jos0lmaA8SRWyIUsWrdD4yWow,4760 -huggingface_hub/inference/_generated/types/text_to_video.py,sha256=xjC9Vp3eovuKEk7qhIeeC8VNJG8W0Kr8PEnOwOC1Ga4,1784 -huggingface_hub/inference/_generated/types/token_classification.py,sha256=bpRwy_1knC11auZaeoVrCyYWBwyJLLKeiS-ypNkDTT8,1909 -huggingface_hub/inference/_generated/types/translation.py,sha256=jfeWNGkZInGTOWP-Tq2dl1rGa8xuUQvZ40PxuOrsBpE,1757 -huggingface_hub/inference/_generated/types/video_classification.py,sha256=TyydjQw2NRLK9sDGzJUVnkDeo848ebmCx588Ur8I9q0,1680 -huggingface_hub/inference/_generated/types/visual_question_answering.py,sha256=AWrQ6qo4gZa3PGedaNpzDFqx5yOYyjhnUB6iuZEj_uo,1673 -huggingface_hub/inference/_generated/types/zero_shot_classification.py,sha256=-PRiAdpXN0wxRrSVe3z8byEvuxcNby89mASU9CbfVzU,1732 -huggingface_hub/inference/_generated/types/zero_shot_image_classification.py,sha256=1alzatw0RA88YUuHfrhRWQ5-Fix-iO3KcxfJV3WQB50,1481 -huggingface_hub/inference/_generated/types/zero_shot_object_detection.py,sha256=sjdpVUN5zW9aYBymLVUs6i5HVk2qkUBO9ysEjHmsXVM,1605 -huggingface_hub/inference/_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -huggingface_hub/inference/_mcp/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/inference/_mcp/__pycache__/_cli_hacks.cpython-310.pyc,, -huggingface_hub/inference/_mcp/__pycache__/agent.cpython-310.pyc,, -huggingface_hub/inference/_mcp/__pycache__/cli.cpython-310.pyc,, -huggingface_hub/inference/_mcp/__pycache__/constants.cpython-310.pyc,, -huggingface_hub/inference/_mcp/__pycache__/mcp_client.cpython-310.pyc,, -huggingface_hub/inference/_mcp/__pycache__/types.cpython-310.pyc,, -huggingface_hub/inference/_mcp/__pycache__/utils.cpython-310.pyc,, -huggingface_hub/inference/_mcp/_cli_hacks.py,sha256=KX9HZJPa1p8ngY3mtYGGlVUXfg4vYbbBRs-8HLToP04,3284 -huggingface_hub/inference/_mcp/agent.py,sha256=ufIzMGHore5n252hV5GZPM0ouDXIl6tv5Jl_5gHXnbg,4250 -huggingface_hub/inference/_mcp/cli.py,sha256=BUw-ZINYw3xQpqMpP0NMQ8sur-lebQTcp7KuzCAIJPo,9811 -huggingface_hub/inference/_mcp/constants.py,sha256=Ws8BujjgZWb5kPAVm4GLE_Rqse63MszHp863EWwoPCI,2487 -huggingface_hub/inference/_mcp/mcp_client.py,sha256=dGp8PhN6aVw4bDnuSySFSiguHUiz-nzhgv89CVdO7pI,17243 -huggingface_hub/inference/_mcp/types.py,sha256=yHNfPsM9MhD06oeKdkbmrBsW-3WhUeqA26fyfRfx_bk,929 -huggingface_hub/inference/_mcp/utils.py,sha256=GI-jVl4AoGTQkpyUIyFmk1YF13bIABbq7hOLHWizBTI,4245 -huggingface_hub/inference/_providers/__init__.py,sha256=k_yHc9aqkgqC302YGw8OitoHO6XD-tny4DDKkazM2gU,10336 -huggingface_hub/inference/_providers/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/_common.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/black_forest_labs.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/cerebras.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/clarifai.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/cohere.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/fal_ai.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/featherless_ai.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/fireworks_ai.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/groq.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/hf_inference.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/hyperbolic.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/nebius.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/novita.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/nscale.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/openai.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/ovhcloud.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/publicai.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/replicate.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/sambanova.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/scaleway.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/together.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/wavespeed.cpython-310.pyc,, -huggingface_hub/inference/_providers/__pycache__/zai_org.cpython-310.pyc,, -huggingface_hub/inference/_providers/_common.py,sha256=fMs5721C0QyUpjQw7bzcNetqS0_oJ37gqceG4iCf7wo,13859 -huggingface_hub/inference/_providers/black_forest_labs.py,sha256=vkjK_-4epSJa2-fLnbcXFzPAgQsGKhykKwd9Np-V2iw,2846 -huggingface_hub/inference/_providers/cerebras.py,sha256=QOJ-1U-os7uE7p6eUnn_P_APq-yQhx28be7c3Tq2EuA,210 -huggingface_hub/inference/_providers/clarifai.py,sha256=1cEXQwhGk4DRKiPCQUa5y-L6okTo4781EImQC8yJVOw,380 -huggingface_hub/inference/_providers/cohere.py,sha256=GqUyCR4j6Re-_27ItwQF2p89Yya4e__EWDP9hTSs9w0,1247 -huggingface_hub/inference/_providers/fal_ai.py,sha256=6zulqIfgfqV8eStuDHafwooK_fsdSA0sZnKECrtnxdk,11815 -huggingface_hub/inference/_providers/featherless_ai.py,sha256=SceM3VsgzDSaCnzVxTFK6JepHaGStptdLlwrX-zsM2g,1376 -huggingface_hub/inference/_providers/fireworks_ai.py,sha256=YfxC8wMU38qpv6xFc5HnHf6qK4x64nt-iwEDTip4C_U,1209 -huggingface_hub/inference/_providers/groq.py,sha256=JTk2JV4ZOlaohho7zLAFQtk92kGVsPmLJ1hmzcwsqvQ,315 -huggingface_hub/inference/_providers/hf_inference.py,sha256=dp15WQQNdbIJhLiRvH3PA651xdf7OjMx3R_1bjKqLxw,9534 -huggingface_hub/inference/_providers/hyperbolic.py,sha256=LiAAiW7diy-ctrDKNYO_2N4Ght9wnvvD7hMo2NYbsNg,1979 -huggingface_hub/inference/_providers/nebius.py,sha256=NQDJoNbFd9FPBA5yWTb_C42NoMeV8edpZCTRoXqtDOM,3574 -huggingface_hub/inference/_providers/novita.py,sha256=AN4csxwKbRvNiaK87o9xVp9krL6mHPk6iv5iat87skA,2508 -huggingface_hub/inference/_providers/nscale.py,sha256=RkyvmYtQbs2RPenF_pxDPMUMZM_botT21zqfVe2hT5Y,1796 -huggingface_hub/inference/_providers/openai.py,sha256=GCVYeNdjWIgpQQ7E_Xv8IebmdhTi0S6WfFosz3nLtps,1089 -huggingface_hub/inference/_providers/ovhcloud.py,sha256=tdmymlkbddMJKV7NRZ-tH2wymbLPFDTqUSXpWJUXyDQ,314 -huggingface_hub/inference/_providers/publicai.py,sha256=1I2W6rORloB5QHSvky4njZO2XKLTwA-kPdNoauoT5rg,210 -huggingface_hub/inference/_providers/replicate.py,sha256=2Wa6S7HLsQ3ShfawZOuK8MQQtuqpkhk-mPNqtHtdk8E,6104 -huggingface_hub/inference/_providers/sambanova.py,sha256=t-J89tab8wut62jXSXl7pAK5mCrovwdgtvbDYK1DHis,2031 -huggingface_hub/inference/_providers/scaleway.py,sha256=Jy81kXWbXCHBpx6xmyzdEfXGSyhUfjKOLHuDSvhHWGo,1209 -huggingface_hub/inference/_providers/together.py,sha256=q32zFvXhmRogWXMSaEFVYS8m9blXI_oy7KPdeal7Wwg,3433 -huggingface_hub/inference/_providers/wavespeed.py,sha256=908rHLPhrbbdmR4EDfkH58N8gg8zcoYy0bvHALbnGoU,5060 -huggingface_hub/inference/_providers/zai_org.py,sha256=ZNp6PrkzNR4ZpU8feNBvsoXmFinT-We_SCoRNx8E7N0,4768 -huggingface_hub/lfs.py,sha256=0Yj3ydggRIAO5Jl9kfFRXJjZyvpjo-siaQBos26K_1g,14151 -huggingface_hub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -huggingface_hub/repocard.py,sha256=eGgvokul8iiCXYuPdrGGyiq6r0YZy_bA91p0SNdmkqw,34973 -huggingface_hub/repocard_data.py,sha256=awhSsLRPrcFM9CurB9mrY40H1bE15yzoXDTVL60yD1U,34079 -huggingface_hub/serialization/__init__.py,sha256=jCiw_vVQYW52gwVfWiqgocf2Q19kGTQlRGVpf-4SLP8,963 -huggingface_hub/serialization/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/serialization/__pycache__/_base.cpython-310.pyc,, -huggingface_hub/serialization/__pycache__/_dduf.cpython-310.pyc,, -huggingface_hub/serialization/__pycache__/_torch.cpython-310.pyc,, -huggingface_hub/serialization/_base.py,sha256=9HZ0W6r77rsUVk5g51_-uglb5KSfHIBMC5YIsVG0woU,8175 -huggingface_hub/serialization/_dduf.py,sha256=KpfM8D9w3UcAM0hhwYdnM8byIiZMUKQnTl25Wb1hHiw,15410 -huggingface_hub/serialization/_torch.py,sha256=__M4aP9zuCJp9TAJLr0r-26LuSao2cofzeo2MPSe-VI,45124 -huggingface_hub/templates/datasetcard_template.md,sha256=W-EMqR6wndbrnZorkVv56URWPG49l7MATGeI015kTvs,5503 -huggingface_hub/templates/modelcard_template.md,sha256=4AqArS3cqdtbit5Bo-DhjcnDFR-pza5hErLLTPM4Yuc,6870 -huggingface_hub/utils/__init__.py,sha256=w7O2buBzUW1akdF9G-t8nbaEkQuDEQLelH685d8Zjow,3894 -huggingface_hub/utils/__pycache__/__init__.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_auth.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_cache_assets.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_cache_manager.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_chunk_utils.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_datetime.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_deprecation.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_dotenv.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_experimental.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_fixes.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_git_credential.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_headers.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_http.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_lfs.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_pagination.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_parsing.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_paths.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_runtime.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_safetensors.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_subprocess.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_telemetry.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_terminal.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_typing.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_validators.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_verification.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_xet.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/_xet_progress_reporting.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/endpoint_helpers.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/insecure_hashlib.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/logging.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/sha.cpython-310.pyc,, -huggingface_hub/utils/__pycache__/tqdm.cpython-310.pyc,, -huggingface_hub/utils/_auth.py,sha256=dtJXLgad9jyH33b3YOGFqbjV8Fi0PPR9GnBxgJqfKK4,8279 -huggingface_hub/utils/_cache_assets.py,sha256=GAefejvj4ZAY1aJ4agyuR-1_IqYo-xznjXA_QYcEQGI,5736 -huggingface_hub/utils/_cache_manager.py,sha256=1Yb3s4jIXudAV1H2nD7mmxi3CcUel8dCmXB06RiexLk,32991 -huggingface_hub/utils/_chunk_utils.py,sha256=MH7-6FwCDZ8noV6dGRytCOJGSfcZmDBvsvVotdI8TvQ,2109 -huggingface_hub/utils/_datetime.py,sha256=kCS5jaKV25kOncX1xujbXsz5iDLcjLcLw85semGNzxQ,2770 -huggingface_hub/utils/_deprecation.py,sha256=4tWi3vBSdvnhA0z_Op-tkAQ0xrJ4TUb0HbPhMiXUnOs,4872 -huggingface_hub/utils/_dotenv.py,sha256=2LLdzpA-LzLxO15GLb9WKT5IGrTurIRmFPrMX1yDzsU,2011 -huggingface_hub/utils/_experimental.py,sha256=3-c8irbn9sJr2CwWbzhGkIrdXKg8_x7BifhHFy32ei8,2470 -huggingface_hub/utils/_fixes.py,sha256=ERTu7OOKLGktAsa-PywPv109e5yjMTMHv5eOdWBadFc,4162 -huggingface_hub/utils/_git_credential.py,sha256=gdQbYZyKEynpqLmtr8lSnCrfPTBzdFdmODmHIgivr4k,4612 -huggingface_hub/utils/_headers.py,sha256=k_ApvA8fJGHc0yNp2IFY8wySM9MQ5UZEpjr1g-fpRJ4,8060 -huggingface_hub/utils/_http.py,sha256=tH-YzLsjoCk6UqaWtksCJZJ8Z6qYzdkKBIuBBZPDZq4,37453 -huggingface_hub/utils/_lfs.py,sha256=EC0Oz6Wiwl8foRNkUOzrETXzAWlbgpnpxo5a410ovFY,3957 -huggingface_hub/utils/_pagination.py,sha256=-6HUYjkSXXy-l0z4iRUBkdW1R_Pv7p6h2Z78HEFEC14,1851 -huggingface_hub/utils/_parsing.py,sha256=T6UCjUh0h731A0Jh-eH5RWcqVQ5m0IyMcXHl5G2YNUs,3021 -huggingface_hub/utils/_paths.py,sha256=UOnpN-pTyD52JPuG553eLJQC8sQ3hWs-paeNqQAvLj4,5291 -huggingface_hub/utils/_runtime.py,sha256=YIbpExk5dxRXGbdwUjTJDBNnZIwo6_5xi4ZjVOPI6Vg,12595 -huggingface_hub/utils/_safetensors.py,sha256=2_xbCsDPsCwR1tyBjJ5MoOHsX4ksocjzc4jS7oGe7_s,4439 -huggingface_hub/utils/_subprocess.py,sha256=9qDWT1a2QF2TmXOQJDlPK6LwzYl9XjXeRadQPn15U14,4612 -huggingface_hub/utils/_telemetry.py,sha256=hlVBh85Cp10Kl4mqIlJLDyGzlrEKCJnqWvNEip7stwo,4884 -huggingface_hub/utils/_terminal.py,sha256=6iiPQfqjkNCo3GfBDAFu1NfGRaZO4AFTYapQDTwNCjs,2354 -huggingface_hub/utils/_typing.py,sha256=cC9p6E8hG2LId8sFWJ9H-cpQozv3asuoww_XiA1-XWI,3617 -huggingface_hub/utils/_validators.py,sha256=A3BkXbpX4KnUD2WFsYOgkXnYdpLiXXG8KbyNdq0qz78,8346 -huggingface_hub/utils/_verification.py,sha256=Ad6gSMcfH4c9WIkg3ecB2kqlChRIQ18c4tNyAGt0HBM,5456 -huggingface_hub/utils/_xet.py,sha256=vaEYYrm5lW7Y_cFSodXjx_TfnkOofIZ-Gh-4Vu7tG_w,8895 -huggingface_hub/utils/_xet_progress_reporting.py,sha256=bxwanhLxigDASflFZVt7S8eENIviguyVg1Q9vFtmDf8,6169 -huggingface_hub/utils/endpoint_helpers.py,sha256=9VtIAlxQ5H_4y30sjCAgbu7XCqAtNLC7aRYxaNn0hLI,2366 -huggingface_hub/utils/insecure_hashlib.py,sha256=z3dVUFvdBZ8kQI_8Vzvvlr3ims-EBiY-SYPdnzIKOkw,1008 -huggingface_hub/utils/logging.py,sha256=N6NXaCcbPbZSF-Oe-TY3ZnmkpmdFVyTOV8ASo-yVXLE,4916 -huggingface_hub/utils/sha.py,sha256=OFnNGCba0sNcT2gUwaVCJnldxlltrHHe0DS_PCpV3C4,2134 -huggingface_hub/utils/tqdm.py,sha256=lhdAR-4zn9cablCDS6240-O2vb4bdTfTbjUW684QWI4,10757 diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/REQUESTED b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/REQUESTED deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/WHEEL b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/WHEEL deleted file mode 100644 index 8acb95590701b87bf84eec079cf4e3989f63b098..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (79.0.1) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/entry_points.txt b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/entry_points.txt deleted file mode 100644 index ab4e46d125b35cd248ddf8f289d96a8452cb1333..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/entry_points.txt +++ /dev/null @@ -1,6 +0,0 @@ -[console_scripts] -hf = huggingface_hub.cli.hf:main -tiny-agents = huggingface_hub.inference._mcp.cli:app - -[fsspec.specs] -hf = huggingface_hub.HfFileSystem diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/licenses/LICENSE b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/licenses/LICENSE deleted file mode 100644 index 261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/top_level.txt b/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/top_level.txt deleted file mode 100644 index 6b964ccca3c1b6766042b3fe3b2707ba25372924..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub-1.4.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -huggingface_hub diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__init__.py b/venv/lib/python3.10/site-packages/huggingface_hub/__init__.py deleted file mode 100644 index 9e4f04bddd58756c91dde5e0f4b2d331bc8ed6ca..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/__init__.py +++ /dev/null @@ -1,1620 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# 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. - -# *********** -# `huggingface_hub` init has 2 modes: -# - Normal usage: -# If imported to use it, all modules and functions are lazy-loaded. This means -# they exist at top level in module but are imported only the first time they are -# used. This way, `from huggingface_hub import something` will import `something` -# quickly without the hassle of importing all the features from `huggingface_hub`. -# - Static check: -# If statically analyzed, all modules and functions are loaded normally. This way -# static typing check works properly as well as autocomplete in text editors and -# IDEs. -# -# The static model imports are done inside the `if TYPE_CHECKING:` statement at -# the bottom of this file. Since module/functions imports are duplicated, it is -# mandatory to make sure to add them twice when adding one. This is checked in the -# `make quality` command. -# -# To update the static imports, please run the following command and commit the changes. -# ``` -# # Use script -# python utils/check_static_imports.py --update-file -# -# # Or run style on codebase -# make style -# ``` -# -# *********** -# Lazy loader vendored from https://github.com/scientific-python/lazy_loader -import importlib -import os -import sys -from typing import TYPE_CHECKING - - -__version__ = "1.4.1" - -# Alphabetical order of definitions is ensured in tests -# WARNING: any comment added in this dictionary definition will be lost when -# re-generating the file ! -_SUBMOD_ATTRS = { - "_commit_scheduler": [ - "CommitScheduler", - ], - "_eval_results": [ - "EvalResultEntry", - "eval_result_entries_to_yaml", - "parse_eval_result_entries", - ], - "_inference_endpoints": [ - "InferenceEndpoint", - "InferenceEndpointError", - "InferenceEndpointStatus", - "InferenceEndpointTimeoutError", - "InferenceEndpointType", - ], - "_jobs_api": [ - "JobAccelerator", - "JobHardware", - "JobInfo", - "JobOwner", - "JobStage", - "JobStatus", - ], - "_login": [ - "auth_list", - "auth_switch", - "interpreter_login", - "login", - "logout", - "notebook_login", - ], - "_oauth": [ - "OAuthInfo", - "OAuthOrgInfo", - "OAuthUserInfo", - "attach_huggingface_oauth", - "parse_huggingface_oauth", - ], - "_snapshot_download": [ - "snapshot_download", - ], - "_space_api": [ - "SpaceHardware", - "SpaceRuntime", - "SpaceStage", - "SpaceStorage", - "SpaceVariable", - ], - "_tensorboard_logger": [ - "HFSummaryWriter", - ], - "_webhooks_payload": [ - "WebhookPayload", - "WebhookPayloadComment", - "WebhookPayloadDiscussion", - "WebhookPayloadDiscussionChanges", - "WebhookPayloadEvent", - "WebhookPayloadMovedTo", - "WebhookPayloadRepo", - "WebhookPayloadUrl", - "WebhookPayloadWebhook", - ], - "_webhooks_server": [ - "WebhooksServer", - "webhook_endpoint", - ], - "cli._cli_utils": [ - "check_cli_update", - "typer_factory", - ], - "community": [ - "Discussion", - "DiscussionComment", - "DiscussionCommit", - "DiscussionEvent", - "DiscussionStatusChange", - "DiscussionTitleChange", - "DiscussionWithDetails", - ], - "constants": [ - "CONFIG_NAME", - "FLAX_WEIGHTS_NAME", - "HUGGINGFACE_CO_URL_HOME", - "HUGGINGFACE_CO_URL_TEMPLATE", - "PYTORCH_WEIGHTS_NAME", - "REPO_TYPE_DATASET", - "REPO_TYPE_MODEL", - "REPO_TYPE_SPACE", - "TF2_WEIGHTS_NAME", - "TF_WEIGHTS_NAME", - "is_offline_mode", - ], - "fastai_utils": [ - "_save_pretrained_fastai", - "from_pretrained_fastai", - "push_to_hub_fastai", - ], - "file_download": [ - "DryRunFileInfo", - "HfFileMetadata", - "_CACHED_NO_EXIST", - "get_hf_file_metadata", - "hf_hub_download", - "hf_hub_url", - "try_to_load_from_cache", - ], - "hf_api": [ - "Collection", - "CollectionItem", - "CommitInfo", - "CommitOperation", - "CommitOperationAdd", - "CommitOperationCopy", - "CommitOperationDelete", - "DatasetInfo", - "GitCommitInfo", - "GitRefInfo", - "GitRefs", - "HfApi", - "ModelInfo", - "Organization", - "RepoFile", - "RepoFolder", - "RepoUrl", - "SpaceInfo", - "User", - "UserLikes", - "WebhookInfo", - "WebhookWatchedItem", - "accept_access_request", - "add_collection_item", - "add_space_secret", - "add_space_variable", - "auth_check", - "cancel_access_request", - "cancel_job", - "change_discussion_status", - "comment_discussion", - "create_branch", - "create_collection", - "create_commit", - "create_discussion", - "create_inference_endpoint", - "create_inference_endpoint_from_catalog", - "create_pull_request", - "create_repo", - "create_scheduled_job", - "create_scheduled_uv_job", - "create_tag", - "create_webhook", - "dataset_info", - "delete_branch", - "delete_collection", - "delete_collection_item", - "delete_file", - "delete_folder", - "delete_inference_endpoint", - "delete_repo", - "delete_scheduled_job", - "delete_space_secret", - "delete_space_storage", - "delete_space_variable", - "delete_tag", - "delete_webhook", - "disable_webhook", - "duplicate_space", - "edit_discussion_comment", - "enable_webhook", - "fetch_job_logs", - "fetch_job_metrics", - "file_exists", - "get_collection", - "get_dataset_tags", - "get_discussion_details", - "get_full_repo_name", - "get_inference_endpoint", - "get_local_safetensors_metadata", - "get_model_tags", - "get_organization_overview", - "get_paths_info", - "get_repo_discussions", - "get_safetensors_metadata", - "get_space_runtime", - "get_space_variables", - "get_user_overview", - "get_webhook", - "grant_access", - "inspect_job", - "inspect_scheduled_job", - "list_accepted_access_requests", - "list_collections", - "list_daily_papers", - "list_datasets", - "list_inference_catalog", - "list_inference_endpoints", - "list_jobs", - "list_jobs_hardware", - "list_lfs_files", - "list_liked_repos", - "list_models", - "list_organization_followers", - "list_organization_members", - "list_papers", - "list_pending_access_requests", - "list_rejected_access_requests", - "list_repo_commits", - "list_repo_files", - "list_repo_likers", - "list_repo_refs", - "list_repo_tree", - "list_spaces", - "list_user_followers", - "list_user_following", - "list_webhooks", - "merge_pull_request", - "model_info", - "move_repo", - "paper_info", - "parse_local_safetensors_file_metadata", - "parse_safetensors_file_metadata", - "pause_inference_endpoint", - "pause_space", - "permanently_delete_lfs_files", - "preupload_lfs_files", - "reject_access_request", - "rename_discussion", - "repo_exists", - "repo_info", - "repo_type_and_id_from_hf_id", - "request_space_hardware", - "request_space_storage", - "restart_space", - "resume_inference_endpoint", - "resume_scheduled_job", - "revision_exists", - "run_as_future", - "run_job", - "run_uv_job", - "scale_to_zero_inference_endpoint", - "set_space_sleep_time", - "space_info", - "super_squash_history", - "suspend_scheduled_job", - "unlike", - "update_collection_item", - "update_collection_metadata", - "update_inference_endpoint", - "update_repo_settings", - "update_webhook", - "upload_file", - "upload_folder", - "upload_large_folder", - "verify_repo_checksums", - "whoami", - ], - "hf_file_system": [ - "HfFileSystem", - "HfFileSystemFile", - "HfFileSystemResolvedPath", - "HfFileSystemStreamFile", - "hffs", - ], - "hub_mixin": [ - "ModelHubMixin", - "PyTorchModelHubMixin", - ], - "inference._client": [ - "InferenceClient", - "InferenceTimeoutError", - ], - "inference._generated._async_client": [ - "AsyncInferenceClient", - ], - "inference._generated.types": [ - "AudioClassificationInput", - "AudioClassificationOutputElement", - "AudioClassificationOutputTransform", - "AudioClassificationParameters", - "AudioToAudioInput", - "AudioToAudioOutputElement", - "AutomaticSpeechRecognitionEarlyStoppingEnum", - "AutomaticSpeechRecognitionGenerationParameters", - "AutomaticSpeechRecognitionInput", - "AutomaticSpeechRecognitionOutput", - "AutomaticSpeechRecognitionOutputChunk", - "AutomaticSpeechRecognitionParameters", - "ChatCompletionInput", - "ChatCompletionInputFunctionDefinition", - "ChatCompletionInputFunctionName", - "ChatCompletionInputGrammarType", - "ChatCompletionInputJSONSchema", - "ChatCompletionInputMessage", - "ChatCompletionInputMessageChunk", - "ChatCompletionInputMessageChunkType", - "ChatCompletionInputResponseFormatJSONObject", - "ChatCompletionInputResponseFormatJSONSchema", - "ChatCompletionInputResponseFormatText", - "ChatCompletionInputStreamOptions", - "ChatCompletionInputTool", - "ChatCompletionInputToolCall", - "ChatCompletionInputToolChoiceClass", - "ChatCompletionInputToolChoiceEnum", - "ChatCompletionInputURL", - "ChatCompletionOutput", - "ChatCompletionOutputComplete", - "ChatCompletionOutputFunctionDefinition", - "ChatCompletionOutputLogprob", - "ChatCompletionOutputLogprobs", - "ChatCompletionOutputMessage", - "ChatCompletionOutputToolCall", - "ChatCompletionOutputTopLogprob", - "ChatCompletionOutputUsage", - "ChatCompletionStreamOutput", - "ChatCompletionStreamOutputChoice", - "ChatCompletionStreamOutputDelta", - "ChatCompletionStreamOutputDeltaToolCall", - "ChatCompletionStreamOutputFunction", - "ChatCompletionStreamOutputLogprob", - "ChatCompletionStreamOutputLogprobs", - "ChatCompletionStreamOutputTopLogprob", - "ChatCompletionStreamOutputUsage", - "DepthEstimationInput", - "DepthEstimationOutput", - "DocumentQuestionAnsweringInput", - "DocumentQuestionAnsweringInputData", - "DocumentQuestionAnsweringOutputElement", - "DocumentQuestionAnsweringParameters", - "FeatureExtractionInput", - "FeatureExtractionInputTruncationDirection", - "FillMaskInput", - "FillMaskOutputElement", - "FillMaskParameters", - "ImageClassificationInput", - "ImageClassificationOutputElement", - "ImageClassificationOutputTransform", - "ImageClassificationParameters", - "ImageSegmentationInput", - "ImageSegmentationOutputElement", - "ImageSegmentationParameters", - "ImageSegmentationSubtask", - "ImageTextToImageInput", - "ImageTextToImageOutput", - "ImageTextToImageParameters", - "ImageTextToImageTargetSize", - "ImageTextToVideoInput", - "ImageTextToVideoOutput", - "ImageTextToVideoParameters", - "ImageTextToVideoTargetSize", - "ImageToImageInput", - "ImageToImageOutput", - "ImageToImageParameters", - "ImageToImageTargetSize", - "ImageToTextEarlyStoppingEnum", - "ImageToTextGenerationParameters", - "ImageToTextInput", - "ImageToTextOutput", - "ImageToTextParameters", - "ImageToVideoInput", - "ImageToVideoOutput", - "ImageToVideoParameters", - "ImageToVideoTargetSize", - "ObjectDetectionBoundingBox", - "ObjectDetectionInput", - "ObjectDetectionOutputElement", - "ObjectDetectionParameters", - "Padding", - "QuestionAnsweringInput", - "QuestionAnsweringInputData", - "QuestionAnsweringOutputElement", - "QuestionAnsweringParameters", - "SentenceSimilarityInput", - "SentenceSimilarityInputData", - "SummarizationInput", - "SummarizationOutput", - "SummarizationParameters", - "SummarizationTruncationStrategy", - "TableQuestionAnsweringInput", - "TableQuestionAnsweringInputData", - "TableQuestionAnsweringOutputElement", - "TableQuestionAnsweringParameters", - "Text2TextGenerationInput", - "Text2TextGenerationOutput", - "Text2TextGenerationParameters", - "Text2TextGenerationTruncationStrategy", - "TextClassificationInput", - "TextClassificationOutputElement", - "TextClassificationOutputTransform", - "TextClassificationParameters", - "TextGenerationInput", - "TextGenerationInputGenerateParameters", - "TextGenerationInputGrammarType", - "TextGenerationOutput", - "TextGenerationOutputBestOfSequence", - "TextGenerationOutputDetails", - "TextGenerationOutputFinishReason", - "TextGenerationOutputPrefillToken", - "TextGenerationOutputToken", - "TextGenerationStreamOutput", - "TextGenerationStreamOutputStreamDetails", - "TextGenerationStreamOutputToken", - "TextToAudioEarlyStoppingEnum", - "TextToAudioGenerationParameters", - "TextToAudioInput", - "TextToAudioOutput", - "TextToAudioParameters", - "TextToImageInput", - "TextToImageOutput", - "TextToImageParameters", - "TextToSpeechEarlyStoppingEnum", - "TextToSpeechGenerationParameters", - "TextToSpeechInput", - "TextToSpeechOutput", - "TextToSpeechParameters", - "TextToVideoInput", - "TextToVideoOutput", - "TextToVideoParameters", - "TokenClassificationAggregationStrategy", - "TokenClassificationInput", - "TokenClassificationOutputElement", - "TokenClassificationParameters", - "TranslationInput", - "TranslationOutput", - "TranslationParameters", - "TranslationTruncationStrategy", - "TypeEnum", - "VideoClassificationInput", - "VideoClassificationOutputElement", - "VideoClassificationOutputTransform", - "VideoClassificationParameters", - "VisualQuestionAnsweringInput", - "VisualQuestionAnsweringInputData", - "VisualQuestionAnsweringOutputElement", - "VisualQuestionAnsweringParameters", - "ZeroShotClassificationInput", - "ZeroShotClassificationOutputElement", - "ZeroShotClassificationParameters", - "ZeroShotImageClassificationInput", - "ZeroShotImageClassificationOutputElement", - "ZeroShotImageClassificationParameters", - "ZeroShotObjectDetectionBoundingBox", - "ZeroShotObjectDetectionInput", - "ZeroShotObjectDetectionOutputElement", - "ZeroShotObjectDetectionParameters", - ], - "inference._mcp.agent": [ - "Agent", - ], - "inference._mcp.mcp_client": [ - "MCPClient", - ], - "repocard": [ - "DatasetCard", - "ModelCard", - "RepoCard", - "SpaceCard", - "metadata_eval_result", - "metadata_load", - "metadata_save", - "metadata_update", - ], - "repocard_data": [ - "CardData", - "DatasetCardData", - "EvalResult", - "ModelCardData", - "SpaceCardData", - ], - "serialization": [ - "StateDictSplit", - "get_torch_storage_id", - "get_torch_storage_size", - "load_state_dict_from_file", - "load_torch_model", - "save_torch_model", - "save_torch_state_dict", - "split_state_dict_into_shards_factory", - "split_torch_state_dict_into_shards", - ], - "serialization._dduf": [ - "DDUFEntry", - "export_entries_as_dduf", - "export_folder_as_dduf", - "read_dduf_file", - ], - "utils": [ - "ASYNC_CLIENT_FACTORY_T", - "CLIENT_FACTORY_T", - "CacheNotFound", - "CachedFileInfo", - "CachedRepoInfo", - "CachedRevisionInfo", - "CorruptedCacheException", - "DeleteCacheStrategy", - "HFCacheInfo", - "cached_assets_path", - "close_session", - "dump_environment_info", - "get_async_session", - "get_session", - "get_token", - "hf_raise_for_status", - "logging", - "scan_cache_dir", - "set_async_client_factory", - "set_client_factory", - ], -} - -# WARNING: __all__ is generated automatically, Any manual edit will be lost when re-generating this file ! -# -# To update the static imports, please run the following command and commit the changes. -# ``` -# # Use script -# python utils/check_all_variable.py --update -# -# # Or run style on codebase -# make style -# ``` - -__all__ = [ - "ASYNC_CLIENT_FACTORY_T", - "Agent", - "AsyncInferenceClient", - "AudioClassificationInput", - "AudioClassificationOutputElement", - "AudioClassificationOutputTransform", - "AudioClassificationParameters", - "AudioToAudioInput", - "AudioToAudioOutputElement", - "AutomaticSpeechRecognitionEarlyStoppingEnum", - "AutomaticSpeechRecognitionGenerationParameters", - "AutomaticSpeechRecognitionInput", - "AutomaticSpeechRecognitionOutput", - "AutomaticSpeechRecognitionOutputChunk", - "AutomaticSpeechRecognitionParameters", - "CLIENT_FACTORY_T", - "CONFIG_NAME", - "CacheNotFound", - "CachedFileInfo", - "CachedRepoInfo", - "CachedRevisionInfo", - "CardData", - "ChatCompletionInput", - "ChatCompletionInputFunctionDefinition", - "ChatCompletionInputFunctionName", - "ChatCompletionInputGrammarType", - "ChatCompletionInputJSONSchema", - "ChatCompletionInputMessage", - "ChatCompletionInputMessageChunk", - "ChatCompletionInputMessageChunkType", - "ChatCompletionInputResponseFormatJSONObject", - "ChatCompletionInputResponseFormatJSONSchema", - "ChatCompletionInputResponseFormatText", - "ChatCompletionInputStreamOptions", - "ChatCompletionInputTool", - "ChatCompletionInputToolCall", - "ChatCompletionInputToolChoiceClass", - "ChatCompletionInputToolChoiceEnum", - "ChatCompletionInputURL", - "ChatCompletionOutput", - "ChatCompletionOutputComplete", - "ChatCompletionOutputFunctionDefinition", - "ChatCompletionOutputLogprob", - "ChatCompletionOutputLogprobs", - "ChatCompletionOutputMessage", - "ChatCompletionOutputToolCall", - "ChatCompletionOutputTopLogprob", - "ChatCompletionOutputUsage", - "ChatCompletionStreamOutput", - "ChatCompletionStreamOutputChoice", - "ChatCompletionStreamOutputDelta", - "ChatCompletionStreamOutputDeltaToolCall", - "ChatCompletionStreamOutputFunction", - "ChatCompletionStreamOutputLogprob", - "ChatCompletionStreamOutputLogprobs", - "ChatCompletionStreamOutputTopLogprob", - "ChatCompletionStreamOutputUsage", - "Collection", - "CollectionItem", - "CommitInfo", - "CommitOperation", - "CommitOperationAdd", - "CommitOperationCopy", - "CommitOperationDelete", - "CommitScheduler", - "CorruptedCacheException", - "DDUFEntry", - "DatasetCard", - "DatasetCardData", - "DatasetInfo", - "DeleteCacheStrategy", - "DepthEstimationInput", - "DepthEstimationOutput", - "Discussion", - "DiscussionComment", - "DiscussionCommit", - "DiscussionEvent", - "DiscussionStatusChange", - "DiscussionTitleChange", - "DiscussionWithDetails", - "DocumentQuestionAnsweringInput", - "DocumentQuestionAnsweringInputData", - "DocumentQuestionAnsweringOutputElement", - "DocumentQuestionAnsweringParameters", - "DryRunFileInfo", - "EvalResult", - "EvalResultEntry", - "FLAX_WEIGHTS_NAME", - "FeatureExtractionInput", - "FeatureExtractionInputTruncationDirection", - "FillMaskInput", - "FillMaskOutputElement", - "FillMaskParameters", - "GitCommitInfo", - "GitRefInfo", - "GitRefs", - "HFCacheInfo", - "HFSummaryWriter", - "HUGGINGFACE_CO_URL_HOME", - "HUGGINGFACE_CO_URL_TEMPLATE", - "HfApi", - "HfFileMetadata", - "HfFileSystem", - "HfFileSystemFile", - "HfFileSystemResolvedPath", - "HfFileSystemStreamFile", - "ImageClassificationInput", - "ImageClassificationOutputElement", - "ImageClassificationOutputTransform", - "ImageClassificationParameters", - "ImageSegmentationInput", - "ImageSegmentationOutputElement", - "ImageSegmentationParameters", - "ImageSegmentationSubtask", - "ImageTextToImageInput", - "ImageTextToImageOutput", - "ImageTextToImageParameters", - "ImageTextToImageTargetSize", - "ImageTextToVideoInput", - "ImageTextToVideoOutput", - "ImageTextToVideoParameters", - "ImageTextToVideoTargetSize", - "ImageToImageInput", - "ImageToImageOutput", - "ImageToImageParameters", - "ImageToImageTargetSize", - "ImageToTextEarlyStoppingEnum", - "ImageToTextGenerationParameters", - "ImageToTextInput", - "ImageToTextOutput", - "ImageToTextParameters", - "ImageToVideoInput", - "ImageToVideoOutput", - "ImageToVideoParameters", - "ImageToVideoTargetSize", - "InferenceClient", - "InferenceEndpoint", - "InferenceEndpointError", - "InferenceEndpointStatus", - "InferenceEndpointTimeoutError", - "InferenceEndpointType", - "InferenceTimeoutError", - "JobAccelerator", - "JobHardware", - "JobInfo", - "JobOwner", - "JobStage", - "JobStatus", - "MCPClient", - "ModelCard", - "ModelCardData", - "ModelHubMixin", - "ModelInfo", - "OAuthInfo", - "OAuthOrgInfo", - "OAuthUserInfo", - "ObjectDetectionBoundingBox", - "ObjectDetectionInput", - "ObjectDetectionOutputElement", - "ObjectDetectionParameters", - "Organization", - "PYTORCH_WEIGHTS_NAME", - "Padding", - "PyTorchModelHubMixin", - "QuestionAnsweringInput", - "QuestionAnsweringInputData", - "QuestionAnsweringOutputElement", - "QuestionAnsweringParameters", - "REPO_TYPE_DATASET", - "REPO_TYPE_MODEL", - "REPO_TYPE_SPACE", - "RepoCard", - "RepoFile", - "RepoFolder", - "RepoUrl", - "SentenceSimilarityInput", - "SentenceSimilarityInputData", - "SpaceCard", - "SpaceCardData", - "SpaceHardware", - "SpaceInfo", - "SpaceRuntime", - "SpaceStage", - "SpaceStorage", - "SpaceVariable", - "StateDictSplit", - "SummarizationInput", - "SummarizationOutput", - "SummarizationParameters", - "SummarizationTruncationStrategy", - "TF2_WEIGHTS_NAME", - "TF_WEIGHTS_NAME", - "TableQuestionAnsweringInput", - "TableQuestionAnsweringInputData", - "TableQuestionAnsweringOutputElement", - "TableQuestionAnsweringParameters", - "Text2TextGenerationInput", - "Text2TextGenerationOutput", - "Text2TextGenerationParameters", - "Text2TextGenerationTruncationStrategy", - "TextClassificationInput", - "TextClassificationOutputElement", - "TextClassificationOutputTransform", - "TextClassificationParameters", - "TextGenerationInput", - "TextGenerationInputGenerateParameters", - "TextGenerationInputGrammarType", - "TextGenerationOutput", - "TextGenerationOutputBestOfSequence", - "TextGenerationOutputDetails", - "TextGenerationOutputFinishReason", - "TextGenerationOutputPrefillToken", - "TextGenerationOutputToken", - "TextGenerationStreamOutput", - "TextGenerationStreamOutputStreamDetails", - "TextGenerationStreamOutputToken", - "TextToAudioEarlyStoppingEnum", - "TextToAudioGenerationParameters", - "TextToAudioInput", - "TextToAudioOutput", - "TextToAudioParameters", - "TextToImageInput", - "TextToImageOutput", - "TextToImageParameters", - "TextToSpeechEarlyStoppingEnum", - "TextToSpeechGenerationParameters", - "TextToSpeechInput", - "TextToSpeechOutput", - "TextToSpeechParameters", - "TextToVideoInput", - "TextToVideoOutput", - "TextToVideoParameters", - "TokenClassificationAggregationStrategy", - "TokenClassificationInput", - "TokenClassificationOutputElement", - "TokenClassificationParameters", - "TranslationInput", - "TranslationOutput", - "TranslationParameters", - "TranslationTruncationStrategy", - "TypeEnum", - "User", - "UserLikes", - "VideoClassificationInput", - "VideoClassificationOutputElement", - "VideoClassificationOutputTransform", - "VideoClassificationParameters", - "VisualQuestionAnsweringInput", - "VisualQuestionAnsweringInputData", - "VisualQuestionAnsweringOutputElement", - "VisualQuestionAnsweringParameters", - "WebhookInfo", - "WebhookPayload", - "WebhookPayloadComment", - "WebhookPayloadDiscussion", - "WebhookPayloadDiscussionChanges", - "WebhookPayloadEvent", - "WebhookPayloadMovedTo", - "WebhookPayloadRepo", - "WebhookPayloadUrl", - "WebhookPayloadWebhook", - "WebhookWatchedItem", - "WebhooksServer", - "ZeroShotClassificationInput", - "ZeroShotClassificationOutputElement", - "ZeroShotClassificationParameters", - "ZeroShotImageClassificationInput", - "ZeroShotImageClassificationOutputElement", - "ZeroShotImageClassificationParameters", - "ZeroShotObjectDetectionBoundingBox", - "ZeroShotObjectDetectionInput", - "ZeroShotObjectDetectionOutputElement", - "ZeroShotObjectDetectionParameters", - "_CACHED_NO_EXIST", - "_save_pretrained_fastai", - "accept_access_request", - "add_collection_item", - "add_space_secret", - "add_space_variable", - "attach_huggingface_oauth", - "auth_check", - "auth_list", - "auth_switch", - "cached_assets_path", - "cancel_access_request", - "cancel_job", - "change_discussion_status", - "check_cli_update", - "close_session", - "comment_discussion", - "create_branch", - "create_collection", - "create_commit", - "create_discussion", - "create_inference_endpoint", - "create_inference_endpoint_from_catalog", - "create_pull_request", - "create_repo", - "create_scheduled_job", - "create_scheduled_uv_job", - "create_tag", - "create_webhook", - "dataset_info", - "delete_branch", - "delete_collection", - "delete_collection_item", - "delete_file", - "delete_folder", - "delete_inference_endpoint", - "delete_repo", - "delete_scheduled_job", - "delete_space_secret", - "delete_space_storage", - "delete_space_variable", - "delete_tag", - "delete_webhook", - "disable_webhook", - "dump_environment_info", - "duplicate_space", - "edit_discussion_comment", - "enable_webhook", - "eval_result_entries_to_yaml", - "export_entries_as_dduf", - "export_folder_as_dduf", - "fetch_job_logs", - "fetch_job_metrics", - "file_exists", - "from_pretrained_fastai", - "get_async_session", - "get_collection", - "get_dataset_tags", - "get_discussion_details", - "get_full_repo_name", - "get_hf_file_metadata", - "get_inference_endpoint", - "get_local_safetensors_metadata", - "get_model_tags", - "get_organization_overview", - "get_paths_info", - "get_repo_discussions", - "get_safetensors_metadata", - "get_session", - "get_space_runtime", - "get_space_variables", - "get_token", - "get_torch_storage_id", - "get_torch_storage_size", - "get_user_overview", - "get_webhook", - "grant_access", - "hf_hub_download", - "hf_hub_url", - "hf_raise_for_status", - "hffs", - "inspect_job", - "inspect_scheduled_job", - "interpreter_login", - "is_offline_mode", - "list_accepted_access_requests", - "list_collections", - "list_daily_papers", - "list_datasets", - "list_inference_catalog", - "list_inference_endpoints", - "list_jobs", - "list_jobs_hardware", - "list_lfs_files", - "list_liked_repos", - "list_models", - "list_organization_followers", - "list_organization_members", - "list_papers", - "list_pending_access_requests", - "list_rejected_access_requests", - "list_repo_commits", - "list_repo_files", - "list_repo_likers", - "list_repo_refs", - "list_repo_tree", - "list_spaces", - "list_user_followers", - "list_user_following", - "list_webhooks", - "load_state_dict_from_file", - "load_torch_model", - "logging", - "login", - "logout", - "merge_pull_request", - "metadata_eval_result", - "metadata_load", - "metadata_save", - "metadata_update", - "model_info", - "move_repo", - "notebook_login", - "paper_info", - "parse_eval_result_entries", - "parse_huggingface_oauth", - "parse_local_safetensors_file_metadata", - "parse_safetensors_file_metadata", - "pause_inference_endpoint", - "pause_space", - "permanently_delete_lfs_files", - "preupload_lfs_files", - "push_to_hub_fastai", - "read_dduf_file", - "reject_access_request", - "rename_discussion", - "repo_exists", - "repo_info", - "repo_type_and_id_from_hf_id", - "request_space_hardware", - "request_space_storage", - "restart_space", - "resume_inference_endpoint", - "resume_scheduled_job", - "revision_exists", - "run_as_future", - "run_job", - "run_uv_job", - "save_torch_model", - "save_torch_state_dict", - "scale_to_zero_inference_endpoint", - "scan_cache_dir", - "set_async_client_factory", - "set_client_factory", - "set_space_sleep_time", - "snapshot_download", - "space_info", - "split_state_dict_into_shards_factory", - "split_torch_state_dict_into_shards", - "super_squash_history", - "suspend_scheduled_job", - "try_to_load_from_cache", - "typer_factory", - "unlike", - "update_collection_item", - "update_collection_metadata", - "update_inference_endpoint", - "update_repo_settings", - "update_webhook", - "upload_file", - "upload_folder", - "upload_large_folder", - "verify_repo_checksums", - "webhook_endpoint", - "whoami", -] - - -def _attach(package_name, submodules=None, submod_attrs=None): - """Attach lazily loaded submodules, functions, or other attributes. - - Typically, modules import submodules and attributes as follows: - - ```py - import mysubmodule - import anothersubmodule - - from .foo import someattr - ``` - - The idea is to replace a package's `__getattr__`, `__dir__`, such that all imports - work exactly the way they would with normal imports, except that the import occurs - upon first use. - - The typical way to call this function, replacing the above imports, is: - - ```python - __getattr__, __dir__ = lazy.attach( - __name__, - ['mysubmodule', 'anothersubmodule'], - {'foo': ['someattr']} - ) - ``` - This functionality requires Python 3.7 or higher. - - Args: - package_name (`str`): - Typically use `__name__`. - submodules (`set`): - List of submodules to attach. - submod_attrs (`dict`): - Dictionary of submodule -> list of attributes / functions. - These attributes are imported as they are used. - - Returns: - __getattr__, __dir__, __all__ - - """ - if submod_attrs is None: - submod_attrs = {} - - if submodules is None: - submodules = set() - else: - submodules = set(submodules) - - attr_to_modules = {attr: mod for mod, attrs in submod_attrs.items() for attr in attrs} - - def __getattr__(name): - if name in submodules: - try: - return importlib.import_module(f"{package_name}.{name}") - except Exception as e: - print(f"Error importing {package_name}.{name}: {e}") - raise - elif name in attr_to_modules: - submod_path = f"{package_name}.{attr_to_modules[name]}" - try: - submod = importlib.import_module(submod_path) - except Exception as e: - print(f"Error importing {submod_path}: {e}") - raise - attr = getattr(submod, name) - - # If the attribute lives in a file (module) with the same - # name as the attribute, ensure that the attribute and *not* - # the module is accessible on the package. - if name == attr_to_modules[name]: - pkg = sys.modules[package_name] - pkg.__dict__[name] = attr - - return attr - else: - raise AttributeError(f"No {package_name} attribute {name}") - - def __dir__(): - return __all__ - - return __getattr__, __dir__ - - -__getattr__, __dir__ = _attach(__name__, submodules=[], submod_attrs=_SUBMOD_ATTRS) - -if os.environ.get("EAGER_IMPORT", ""): - for attr in __all__: - __getattr__(attr) - -# WARNING: any content below this statement is generated automatically. Any manual edit -# will be lost when re-generating this file ! -# -# To update the static imports, please run the following command and commit the changes. -# ``` -# # Use script -# python utils/check_static_imports.py --update -# -# # Or run style on codebase -# make style -# ``` -if TYPE_CHECKING: # pragma: no cover - from ._commit_scheduler import CommitScheduler # noqa: F401 - from ._eval_results import ( - EvalResultEntry, # noqa: F401 - eval_result_entries_to_yaml, # noqa: F401 - parse_eval_result_entries, # noqa: F401 - ) - from ._inference_endpoints import ( - InferenceEndpoint, # noqa: F401 - InferenceEndpointError, # noqa: F401 - InferenceEndpointStatus, # noqa: F401 - InferenceEndpointTimeoutError, # noqa: F401 - InferenceEndpointType, # noqa: F401 - ) - from ._jobs_api import ( - JobAccelerator, # noqa: F401 - JobHardware, # noqa: F401 - JobInfo, # noqa: F401 - JobOwner, # noqa: F401 - JobStage, # noqa: F401 - JobStatus, # noqa: F401 - ) - from ._login import ( - auth_list, # noqa: F401 - auth_switch, # noqa: F401 - interpreter_login, # noqa: F401 - login, # noqa: F401 - logout, # noqa: F401 - notebook_login, # noqa: F401 - ) - from ._oauth import ( - OAuthInfo, # noqa: F401 - OAuthOrgInfo, # noqa: F401 - OAuthUserInfo, # noqa: F401 - attach_huggingface_oauth, # noqa: F401 - parse_huggingface_oauth, # noqa: F401 - ) - from ._snapshot_download import snapshot_download # noqa: F401 - from ._space_api import ( - SpaceHardware, # noqa: F401 - SpaceRuntime, # noqa: F401 - SpaceStage, # noqa: F401 - SpaceStorage, # noqa: F401 - SpaceVariable, # noqa: F401 - ) - from ._tensorboard_logger import HFSummaryWriter # noqa: F401 - from ._webhooks_payload import ( - WebhookPayload, # noqa: F401 - WebhookPayloadComment, # noqa: F401 - WebhookPayloadDiscussion, # noqa: F401 - WebhookPayloadDiscussionChanges, # noqa: F401 - WebhookPayloadEvent, # noqa: F401 - WebhookPayloadMovedTo, # noqa: F401 - WebhookPayloadRepo, # noqa: F401 - WebhookPayloadUrl, # noqa: F401 - WebhookPayloadWebhook, # noqa: F401 - ) - from ._webhooks_server import ( - WebhooksServer, # noqa: F401 - webhook_endpoint, # noqa: F401 - ) - from .cli._cli_utils import ( - check_cli_update, # noqa: F401 - typer_factory, # noqa: F401 - ) - from .community import ( - Discussion, # noqa: F401 - DiscussionComment, # noqa: F401 - DiscussionCommit, # noqa: F401 - DiscussionEvent, # noqa: F401 - DiscussionStatusChange, # noqa: F401 - DiscussionTitleChange, # noqa: F401 - DiscussionWithDetails, # noqa: F401 - ) - from .constants import ( - CONFIG_NAME, # noqa: F401 - FLAX_WEIGHTS_NAME, # noqa: F401 - HUGGINGFACE_CO_URL_HOME, # noqa: F401 - HUGGINGFACE_CO_URL_TEMPLATE, # noqa: F401 - PYTORCH_WEIGHTS_NAME, # noqa: F401 - REPO_TYPE_DATASET, # noqa: F401 - REPO_TYPE_MODEL, # noqa: F401 - REPO_TYPE_SPACE, # noqa: F401 - TF2_WEIGHTS_NAME, # noqa: F401 - TF_WEIGHTS_NAME, # noqa: F401 - is_offline_mode, # noqa: F401 - ) - from .fastai_utils import ( - _save_pretrained_fastai, # noqa: F401 - from_pretrained_fastai, # noqa: F401 - push_to_hub_fastai, # noqa: F401 - ) - from .file_download import ( - _CACHED_NO_EXIST, # noqa: F401 - DryRunFileInfo, # noqa: F401 - HfFileMetadata, # noqa: F401 - get_hf_file_metadata, # noqa: F401 - hf_hub_download, # noqa: F401 - hf_hub_url, # noqa: F401 - try_to_load_from_cache, # noqa: F401 - ) - from .hf_api import ( - Collection, # noqa: F401 - CollectionItem, # noqa: F401 - CommitInfo, # noqa: F401 - CommitOperation, # noqa: F401 - CommitOperationAdd, # noqa: F401 - CommitOperationCopy, # noqa: F401 - CommitOperationDelete, # noqa: F401 - DatasetInfo, # noqa: F401 - GitCommitInfo, # noqa: F401 - GitRefInfo, # noqa: F401 - GitRefs, # noqa: F401 - HfApi, # noqa: F401 - ModelInfo, # noqa: F401 - Organization, # noqa: F401 - RepoFile, # noqa: F401 - RepoFolder, # noqa: F401 - RepoUrl, # noqa: F401 - SpaceInfo, # noqa: F401 - User, # noqa: F401 - UserLikes, # noqa: F401 - WebhookInfo, # noqa: F401 - WebhookWatchedItem, # noqa: F401 - accept_access_request, # noqa: F401 - add_collection_item, # noqa: F401 - add_space_secret, # noqa: F401 - add_space_variable, # noqa: F401 - auth_check, # noqa: F401 - cancel_access_request, # noqa: F401 - cancel_job, # noqa: F401 - change_discussion_status, # noqa: F401 - comment_discussion, # noqa: F401 - create_branch, # noqa: F401 - create_collection, # noqa: F401 - create_commit, # noqa: F401 - create_discussion, # noqa: F401 - create_inference_endpoint, # noqa: F401 - create_inference_endpoint_from_catalog, # noqa: F401 - create_pull_request, # noqa: F401 - create_repo, # noqa: F401 - create_scheduled_job, # noqa: F401 - create_scheduled_uv_job, # noqa: F401 - create_tag, # noqa: F401 - create_webhook, # noqa: F401 - dataset_info, # noqa: F401 - delete_branch, # noqa: F401 - delete_collection, # noqa: F401 - delete_collection_item, # noqa: F401 - delete_file, # noqa: F401 - delete_folder, # noqa: F401 - delete_inference_endpoint, # noqa: F401 - delete_repo, # noqa: F401 - delete_scheduled_job, # noqa: F401 - delete_space_secret, # noqa: F401 - delete_space_storage, # noqa: F401 - delete_space_variable, # noqa: F401 - delete_tag, # noqa: F401 - delete_webhook, # noqa: F401 - disable_webhook, # noqa: F401 - duplicate_space, # noqa: F401 - edit_discussion_comment, # noqa: F401 - enable_webhook, # noqa: F401 - fetch_job_logs, # noqa: F401 - fetch_job_metrics, # noqa: F401 - file_exists, # noqa: F401 - get_collection, # noqa: F401 - get_dataset_tags, # noqa: F401 - get_discussion_details, # noqa: F401 - get_full_repo_name, # noqa: F401 - get_inference_endpoint, # noqa: F401 - get_local_safetensors_metadata, # noqa: F401 - get_model_tags, # noqa: F401 - get_organization_overview, # noqa: F401 - get_paths_info, # noqa: F401 - get_repo_discussions, # noqa: F401 - get_safetensors_metadata, # noqa: F401 - get_space_runtime, # noqa: F401 - get_space_variables, # noqa: F401 - get_user_overview, # noqa: F401 - get_webhook, # noqa: F401 - grant_access, # noqa: F401 - inspect_job, # noqa: F401 - inspect_scheduled_job, # noqa: F401 - list_accepted_access_requests, # noqa: F401 - list_collections, # noqa: F401 - list_daily_papers, # noqa: F401 - list_datasets, # noqa: F401 - list_inference_catalog, # noqa: F401 - list_inference_endpoints, # noqa: F401 - list_jobs, # noqa: F401 - list_jobs_hardware, # noqa: F401 - list_lfs_files, # noqa: F401 - list_liked_repos, # noqa: F401 - list_models, # noqa: F401 - list_organization_followers, # noqa: F401 - list_organization_members, # noqa: F401 - list_papers, # noqa: F401 - list_pending_access_requests, # noqa: F401 - list_rejected_access_requests, # noqa: F401 - list_repo_commits, # noqa: F401 - list_repo_files, # noqa: F401 - list_repo_likers, # noqa: F401 - list_repo_refs, # noqa: F401 - list_repo_tree, # noqa: F401 - list_spaces, # noqa: F401 - list_user_followers, # noqa: F401 - list_user_following, # noqa: F401 - list_webhooks, # noqa: F401 - merge_pull_request, # noqa: F401 - model_info, # noqa: F401 - move_repo, # noqa: F401 - paper_info, # noqa: F401 - parse_local_safetensors_file_metadata, # noqa: F401 - parse_safetensors_file_metadata, # noqa: F401 - pause_inference_endpoint, # noqa: F401 - pause_space, # noqa: F401 - permanently_delete_lfs_files, # noqa: F401 - preupload_lfs_files, # noqa: F401 - reject_access_request, # noqa: F401 - rename_discussion, # noqa: F401 - repo_exists, # noqa: F401 - repo_info, # noqa: F401 - repo_type_and_id_from_hf_id, # noqa: F401 - request_space_hardware, # noqa: F401 - request_space_storage, # noqa: F401 - restart_space, # noqa: F401 - resume_inference_endpoint, # noqa: F401 - resume_scheduled_job, # noqa: F401 - revision_exists, # noqa: F401 - run_as_future, # noqa: F401 - run_job, # noqa: F401 - run_uv_job, # noqa: F401 - scale_to_zero_inference_endpoint, # noqa: F401 - set_space_sleep_time, # noqa: F401 - space_info, # noqa: F401 - super_squash_history, # noqa: F401 - suspend_scheduled_job, # noqa: F401 - unlike, # noqa: F401 - update_collection_item, # noqa: F401 - update_collection_metadata, # noqa: F401 - update_inference_endpoint, # noqa: F401 - update_repo_settings, # noqa: F401 - update_webhook, # noqa: F401 - upload_file, # noqa: F401 - upload_folder, # noqa: F401 - upload_large_folder, # noqa: F401 - verify_repo_checksums, # noqa: F401 - whoami, # noqa: F401 - ) - from .hf_file_system import ( - HfFileSystem, # noqa: F401 - HfFileSystemFile, # noqa: F401 - HfFileSystemResolvedPath, # noqa: F401 - HfFileSystemStreamFile, # noqa: F401 - hffs, # noqa: F401 - ) - from .hub_mixin import ( - ModelHubMixin, # noqa: F401 - PyTorchModelHubMixin, # noqa: F401 - ) - from .inference._client import ( - InferenceClient, # noqa: F401 - InferenceTimeoutError, # noqa: F401 - ) - from .inference._generated._async_client import AsyncInferenceClient # noqa: F401 - from .inference._generated.types import ( - AudioClassificationInput, # noqa: F401 - AudioClassificationOutputElement, # noqa: F401 - AudioClassificationOutputTransform, # noqa: F401 - AudioClassificationParameters, # noqa: F401 - AudioToAudioInput, # noqa: F401 - AudioToAudioOutputElement, # noqa: F401 - AutomaticSpeechRecognitionEarlyStoppingEnum, # noqa: F401 - AutomaticSpeechRecognitionGenerationParameters, # noqa: F401 - AutomaticSpeechRecognitionInput, # noqa: F401 - AutomaticSpeechRecognitionOutput, # noqa: F401 - AutomaticSpeechRecognitionOutputChunk, # noqa: F401 - AutomaticSpeechRecognitionParameters, # noqa: F401 - ChatCompletionInput, # noqa: F401 - ChatCompletionInputFunctionDefinition, # noqa: F401 - ChatCompletionInputFunctionName, # noqa: F401 - ChatCompletionInputGrammarType, # noqa: F401 - ChatCompletionInputJSONSchema, # noqa: F401 - ChatCompletionInputMessage, # noqa: F401 - ChatCompletionInputMessageChunk, # noqa: F401 - ChatCompletionInputMessageChunkType, # noqa: F401 - ChatCompletionInputResponseFormatJSONObject, # noqa: F401 - ChatCompletionInputResponseFormatJSONSchema, # noqa: F401 - ChatCompletionInputResponseFormatText, # noqa: F401 - ChatCompletionInputStreamOptions, # noqa: F401 - ChatCompletionInputTool, # noqa: F401 - ChatCompletionInputToolCall, # noqa: F401 - ChatCompletionInputToolChoiceClass, # noqa: F401 - ChatCompletionInputToolChoiceEnum, # noqa: F401 - ChatCompletionInputURL, # noqa: F401 - ChatCompletionOutput, # noqa: F401 - ChatCompletionOutputComplete, # noqa: F401 - ChatCompletionOutputFunctionDefinition, # noqa: F401 - ChatCompletionOutputLogprob, # noqa: F401 - ChatCompletionOutputLogprobs, # noqa: F401 - ChatCompletionOutputMessage, # noqa: F401 - ChatCompletionOutputToolCall, # noqa: F401 - ChatCompletionOutputTopLogprob, # noqa: F401 - ChatCompletionOutputUsage, # noqa: F401 - ChatCompletionStreamOutput, # noqa: F401 - ChatCompletionStreamOutputChoice, # noqa: F401 - ChatCompletionStreamOutputDelta, # noqa: F401 - ChatCompletionStreamOutputDeltaToolCall, # noqa: F401 - ChatCompletionStreamOutputFunction, # noqa: F401 - ChatCompletionStreamOutputLogprob, # noqa: F401 - ChatCompletionStreamOutputLogprobs, # noqa: F401 - ChatCompletionStreamOutputTopLogprob, # noqa: F401 - ChatCompletionStreamOutputUsage, # noqa: F401 - DepthEstimationInput, # noqa: F401 - DepthEstimationOutput, # noqa: F401 - DocumentQuestionAnsweringInput, # noqa: F401 - DocumentQuestionAnsweringInputData, # noqa: F401 - DocumentQuestionAnsweringOutputElement, # noqa: F401 - DocumentQuestionAnsweringParameters, # noqa: F401 - FeatureExtractionInput, # noqa: F401 - FeatureExtractionInputTruncationDirection, # noqa: F401 - FillMaskInput, # noqa: F401 - FillMaskOutputElement, # noqa: F401 - FillMaskParameters, # noqa: F401 - ImageClassificationInput, # noqa: F401 - ImageClassificationOutputElement, # noqa: F401 - ImageClassificationOutputTransform, # noqa: F401 - ImageClassificationParameters, # noqa: F401 - ImageSegmentationInput, # noqa: F401 - ImageSegmentationOutputElement, # noqa: F401 - ImageSegmentationParameters, # noqa: F401 - ImageSegmentationSubtask, # noqa: F401 - ImageTextToImageInput, # noqa: F401 - ImageTextToImageOutput, # noqa: F401 - ImageTextToImageParameters, # noqa: F401 - ImageTextToImageTargetSize, # noqa: F401 - ImageTextToVideoInput, # noqa: F401 - ImageTextToVideoOutput, # noqa: F401 - ImageTextToVideoParameters, # noqa: F401 - ImageTextToVideoTargetSize, # noqa: F401 - ImageToImageInput, # noqa: F401 - ImageToImageOutput, # noqa: F401 - ImageToImageParameters, # noqa: F401 - ImageToImageTargetSize, # noqa: F401 - ImageToTextEarlyStoppingEnum, # noqa: F401 - ImageToTextGenerationParameters, # noqa: F401 - ImageToTextInput, # noqa: F401 - ImageToTextOutput, # noqa: F401 - ImageToTextParameters, # noqa: F401 - ImageToVideoInput, # noqa: F401 - ImageToVideoOutput, # noqa: F401 - ImageToVideoParameters, # noqa: F401 - ImageToVideoTargetSize, # noqa: F401 - ObjectDetectionBoundingBox, # noqa: F401 - ObjectDetectionInput, # noqa: F401 - ObjectDetectionOutputElement, # noqa: F401 - ObjectDetectionParameters, # noqa: F401 - Padding, # noqa: F401 - QuestionAnsweringInput, # noqa: F401 - QuestionAnsweringInputData, # noqa: F401 - QuestionAnsweringOutputElement, # noqa: F401 - QuestionAnsweringParameters, # noqa: F401 - SentenceSimilarityInput, # noqa: F401 - SentenceSimilarityInputData, # noqa: F401 - SummarizationInput, # noqa: F401 - SummarizationOutput, # noqa: F401 - SummarizationParameters, # noqa: F401 - SummarizationTruncationStrategy, # noqa: F401 - TableQuestionAnsweringInput, # noqa: F401 - TableQuestionAnsweringInputData, # noqa: F401 - TableQuestionAnsweringOutputElement, # noqa: F401 - TableQuestionAnsweringParameters, # noqa: F401 - Text2TextGenerationInput, # noqa: F401 - Text2TextGenerationOutput, # noqa: F401 - Text2TextGenerationParameters, # noqa: F401 - Text2TextGenerationTruncationStrategy, # noqa: F401 - TextClassificationInput, # noqa: F401 - TextClassificationOutputElement, # noqa: F401 - TextClassificationOutputTransform, # noqa: F401 - TextClassificationParameters, # noqa: F401 - TextGenerationInput, # noqa: F401 - TextGenerationInputGenerateParameters, # noqa: F401 - TextGenerationInputGrammarType, # noqa: F401 - TextGenerationOutput, # noqa: F401 - TextGenerationOutputBestOfSequence, # noqa: F401 - TextGenerationOutputDetails, # noqa: F401 - TextGenerationOutputFinishReason, # noqa: F401 - TextGenerationOutputPrefillToken, # noqa: F401 - TextGenerationOutputToken, # noqa: F401 - TextGenerationStreamOutput, # noqa: F401 - TextGenerationStreamOutputStreamDetails, # noqa: F401 - TextGenerationStreamOutputToken, # noqa: F401 - TextToAudioEarlyStoppingEnum, # noqa: F401 - TextToAudioGenerationParameters, # noqa: F401 - TextToAudioInput, # noqa: F401 - TextToAudioOutput, # noqa: F401 - TextToAudioParameters, # noqa: F401 - TextToImageInput, # noqa: F401 - TextToImageOutput, # noqa: F401 - TextToImageParameters, # noqa: F401 - TextToSpeechEarlyStoppingEnum, # noqa: F401 - TextToSpeechGenerationParameters, # noqa: F401 - TextToSpeechInput, # noqa: F401 - TextToSpeechOutput, # noqa: F401 - TextToSpeechParameters, # noqa: F401 - TextToVideoInput, # noqa: F401 - TextToVideoOutput, # noqa: F401 - TextToVideoParameters, # noqa: F401 - TokenClassificationAggregationStrategy, # noqa: F401 - TokenClassificationInput, # noqa: F401 - TokenClassificationOutputElement, # noqa: F401 - TokenClassificationParameters, # noqa: F401 - TranslationInput, # noqa: F401 - TranslationOutput, # noqa: F401 - TranslationParameters, # noqa: F401 - TranslationTruncationStrategy, # noqa: F401 - TypeEnum, # noqa: F401 - VideoClassificationInput, # noqa: F401 - VideoClassificationOutputElement, # noqa: F401 - VideoClassificationOutputTransform, # noqa: F401 - VideoClassificationParameters, # noqa: F401 - VisualQuestionAnsweringInput, # noqa: F401 - VisualQuestionAnsweringInputData, # noqa: F401 - VisualQuestionAnsweringOutputElement, # noqa: F401 - VisualQuestionAnsweringParameters, # noqa: F401 - ZeroShotClassificationInput, # noqa: F401 - ZeroShotClassificationOutputElement, # noqa: F401 - ZeroShotClassificationParameters, # noqa: F401 - ZeroShotImageClassificationInput, # noqa: F401 - ZeroShotImageClassificationOutputElement, # noqa: F401 - ZeroShotImageClassificationParameters, # noqa: F401 - ZeroShotObjectDetectionBoundingBox, # noqa: F401 - ZeroShotObjectDetectionInput, # noqa: F401 - ZeroShotObjectDetectionOutputElement, # noqa: F401 - ZeroShotObjectDetectionParameters, # noqa: F401 - ) - from .inference._mcp.agent import Agent # noqa: F401 - from .inference._mcp.mcp_client import MCPClient # noqa: F401 - from .repocard import ( - DatasetCard, # noqa: F401 - ModelCard, # noqa: F401 - RepoCard, # noqa: F401 - SpaceCard, # noqa: F401 - metadata_eval_result, # noqa: F401 - metadata_load, # noqa: F401 - metadata_save, # noqa: F401 - metadata_update, # noqa: F401 - ) - from .repocard_data import ( - CardData, # noqa: F401 - DatasetCardData, # noqa: F401 - EvalResult, # noqa: F401 - ModelCardData, # noqa: F401 - SpaceCardData, # noqa: F401 - ) - from .serialization import ( - StateDictSplit, # noqa: F401 - get_torch_storage_id, # noqa: F401 - get_torch_storage_size, # noqa: F401 - load_state_dict_from_file, # noqa: F401 - load_torch_model, # noqa: F401 - save_torch_model, # noqa: F401 - save_torch_state_dict, # noqa: F401 - split_state_dict_into_shards_factory, # noqa: F401 - split_torch_state_dict_into_shards, # noqa: F401 - ) - from .serialization._dduf import ( - DDUFEntry, # noqa: F401 - export_entries_as_dduf, # noqa: F401 - export_folder_as_dduf, # noqa: F401 - read_dduf_file, # noqa: F401 - ) - from .utils import ( - ASYNC_CLIENT_FACTORY_T, # noqa: F401 - CLIENT_FACTORY_T, # noqa: F401 - CachedFileInfo, # noqa: F401 - CachedRepoInfo, # noqa: F401 - CachedRevisionInfo, # noqa: F401 - CacheNotFound, # noqa: F401 - CorruptedCacheException, # noqa: F401 - DeleteCacheStrategy, # noqa: F401 - HFCacheInfo, # noqa: F401 - cached_assets_path, # noqa: F401 - close_session, # noqa: F401 - dump_environment_info, # noqa: F401 - get_async_session, # noqa: F401 - get_session, # noqa: F401 - get_token, # noqa: F401 - hf_raise_for_status, # noqa: F401 - logging, # noqa: F401 - scan_cache_dir, # noqa: F401 - set_async_client_factory, # noqa: F401 - set_client_factory, # noqa: F401 - ) diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index ff0770e1407f96351b74aefccc58f72ea7415d3e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_commit_api.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_commit_api.cpython-310.pyc deleted file mode 100644 index b7e62d9516069cd1ac78eb58a24048090776ad7f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_commit_api.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_commit_scheduler.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_commit_scheduler.cpython-310.pyc deleted file mode 100644 index 7f1d8774fe2eeb58e9eda0e3ccc15dd2bc8e5fa1..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_commit_scheduler.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_eval_results.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_eval_results.cpython-310.pyc deleted file mode 100644 index 3c54c71cd2cf67ff4c660e795f2a78d4ed6b6487..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_eval_results.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_inference_endpoints.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_inference_endpoints.cpython-310.pyc deleted file mode 100644 index b36aaf63d8182ceccc5df13fbc6a8450d96ae4ce..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_inference_endpoints.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_jobs_api.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_jobs_api.cpython-310.pyc deleted file mode 100644 index 0e35173f25f1e9a8f9d8152609df617b36f9c62f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_jobs_api.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_local_folder.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_local_folder.cpython-310.pyc deleted file mode 100644 index ddddf41c0f371f763196893d34f8271dd110881d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_local_folder.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_login.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_login.cpython-310.pyc deleted file mode 100644 index 889577ee28e388e74b226b3f3b8db5d60efb5d6a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_login.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_oauth.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_oauth.cpython-310.pyc deleted file mode 100644 index 24a3eb50d4331a21df585e0df0ce6e9b4cbba49d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_oauth.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_snapshot_download.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_snapshot_download.cpython-310.pyc deleted file mode 100644 index c8767fb700bc6544f6596651942ae03e1e222a21..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_snapshot_download.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_space_api.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_space_api.cpython-310.pyc deleted file mode 100644 index 85851c35089ef3b238950611b14f61547ba04993..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_space_api.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_tensorboard_logger.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_tensorboard_logger.cpython-310.pyc deleted file mode 100644 index 609392bcda79a7e1bd7cd56cb5b7d5c78bc772da..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_tensorboard_logger.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_upload_large_folder.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_upload_large_folder.cpython-310.pyc deleted file mode 100644 index 04f86a61647ac1548312d0c6e8b6b379accdae75..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_upload_large_folder.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_webhooks_payload.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_webhooks_payload.cpython-310.pyc deleted file mode 100644 index 2bec19bea0bf18bdb38e04316121d0a136aa3e38..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_webhooks_payload.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_webhooks_server.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_webhooks_server.cpython-310.pyc deleted file mode 100644 index d3352b188ad71866110b9e1807a306c3dfae7d88..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/_webhooks_server.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/community.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/community.cpython-310.pyc deleted file mode 100644 index 3d47aaef7210ef87915d37c63071e7accff48162..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/community.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/constants.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/constants.cpython-310.pyc deleted file mode 100644 index 41e00ed3a38d3ea55fe2367492d5713b87b27b9a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/constants.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/dataclasses.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/dataclasses.cpython-310.pyc deleted file mode 100644 index 597c6bfe0cdd62ac701716008bdce9c0d30ff73e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/dataclasses.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/errors.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/errors.cpython-310.pyc deleted file mode 100644 index 557772ed852c5c396c2dba5913953a57a9936143..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/errors.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/fastai_utils.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/fastai_utils.cpython-310.pyc deleted file mode 100644 index 4473e03ddae7d737967b4cd9bba633013bee353c..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/fastai_utils.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/file_download.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/file_download.cpython-310.pyc deleted file mode 100644 index 7bffc0ce1f854b76d4bd95b9f1732cd0b9cbf81e..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/file_download.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hf_api.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hf_api.cpython-310.pyc deleted file mode 100644 index 8220a8853487f871cd24cd476318ddc220ae1313..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hf_api.cpython-310.pyc +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:beef8ee2404a288f20bb5eabf4fad9123e82657f966c9d1c09207a649ffb54ec -size 425424 diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hf_file_system.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hf_file_system.cpython-310.pyc deleted file mode 100644 index 450f8cc44374a3f80f9d4fc2cae033793b8a45c6..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hf_file_system.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hub_mixin.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hub_mixin.cpython-310.pyc deleted file mode 100644 index d6e4bc1a028283e3bc27d4b9602fd1c2bc62ce5d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/hub_mixin.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/lfs.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/lfs.cpython-310.pyc deleted file mode 100644 index 56e18426d8da7e9bb373159c16b95a4f9457cb21..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/lfs.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/repocard.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/repocard.cpython-310.pyc deleted file mode 100644 index 6ebb8ebe49bb4ed67df57dabec35a7d523134544..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/repocard.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/repocard_data.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/repocard_data.cpython-310.pyc deleted file mode 100644 index 931dbf782e17f6f77a222ca5b0241982ec571e48..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/__pycache__/repocard_data.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_commit_api.py b/venv/lib/python3.10/site-packages/huggingface_hub/_commit_api.py deleted file mode 100644 index f93be55a454a056542a1b33845fb52db3bbd691b..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_commit_api.py +++ /dev/null @@ -1,966 +0,0 @@ -""" -Type definitions and utilities for the `create_commit` API -""" - -import base64 -import io -import os -import warnings -from collections import defaultdict -from contextlib import contextmanager -from dataclasses import dataclass, field -from itertools import groupby -from pathlib import Path, PurePosixPath -from typing import TYPE_CHECKING, Any, BinaryIO, Iterable, Iterator, Literal, Optional, Union - -from tqdm.contrib.concurrent import thread_map - -from . import constants -from .errors import EntryNotFoundError, HfHubHTTPError, XetAuthorizationError, XetRefreshTokenError -from .file_download import hf_hub_url -from .lfs import UploadInfo, lfs_upload, post_lfs_batch_info -from .utils import ( - FORBIDDEN_FOLDERS, - XetTokenType, - are_progress_bars_disabled, - chunk_iterable, - fetch_xet_connection_info_from_repo_info, - get_session, - hf_raise_for_status, - http_backoff, - logging, - sha, - tqdm_stream_file, - validate_hf_hub_args, -) -from .utils import tqdm as hf_tqdm -from .utils._runtime import is_xet_available - - -if TYPE_CHECKING: - from .hf_api import RepoFile - - -logger = logging.get_logger(__name__) - - -UploadMode = Literal["lfs", "regular"] - -# Max is 1,000 per request on the Hub for HfApi.get_paths_info -# Otherwise we get: -# HfHubHTTPError: 413 Client Error: Payload Too Large for url: https://huggingface.co/api/datasets/xxx (Request ID: xxx)\n\ntoo many parameters -# See https://github.com/huggingface/huggingface_hub/issues/1503 -FETCH_LFS_BATCH_SIZE = 500 - -UPLOAD_BATCH_MAX_NUM_FILES = 256 - - -@dataclass -class CommitOperationDelete: - """ - Data structure holding necessary info to delete a file or a folder from a repository - on the Hub. - - Args: - path_in_repo (`str`): - Relative filepath in the repo, for example: `"checkpoints/1fec34a/weights.bin"` - for a file or `"checkpoints/1fec34a/"` for a folder. - is_folder (`bool` or `Literal["auto"]`, *optional*) - Whether the Delete Operation applies to a folder or not. If "auto", the path - type (file or folder) is guessed automatically by looking if path ends with - a "/" (folder) or not (file). To explicitly set the path type, you can set - `is_folder=True` or `is_folder=False`. - """ - - path_in_repo: str - is_folder: Union[bool, Literal["auto"]] = "auto" - - def __post_init__(self): - self.path_in_repo = _validate_path_in_repo(self.path_in_repo) - - if self.is_folder == "auto": - self.is_folder = self.path_in_repo.endswith("/") - if not isinstance(self.is_folder, bool): - raise ValueError( - f"Wrong value for `is_folder`. Must be one of [`True`, `False`, `'auto'`]. Got '{self.is_folder}'." - ) - - -@dataclass -class CommitOperationCopy: - """ - Data structure holding necessary info to copy a file in a repository on the Hub. - - Limitations: - - Only LFS files can be copied. To copy a regular file, you need to download it locally and re-upload it - - Cross-repository copies are not supported. - - Note: you can combine a [`CommitOperationCopy`] and a [`CommitOperationDelete`] to rename an LFS file on the Hub. - - Args: - src_path_in_repo (`str`): - Relative filepath in the repo of the file to be copied, e.g. `"checkpoints/1fec34a/weights.bin"`. - path_in_repo (`str`): - Relative filepath in the repo where to copy the file, e.g. `"checkpoints/1fec34a/weights_copy.bin"`. - src_revision (`str`, *optional*): - The git revision of the file to be copied. Can be any valid git revision. - Default to the target commit revision. - """ - - src_path_in_repo: str - path_in_repo: str - src_revision: Optional[str] = None - # set to the OID of the file to be copied if it has already been uploaded - # useful to determine if a commit will be empty or not. - _src_oid: Optional[str] = None - # set to the OID of the file to copy to if it has already been uploaded - # useful to determine if a commit will be empty or not. - _dest_oid: Optional[str] = None - - def __post_init__(self): - self.src_path_in_repo = _validate_path_in_repo(self.src_path_in_repo) - self.path_in_repo = _validate_path_in_repo(self.path_in_repo) - - -@dataclass -class CommitOperationAdd: - """ - Data structure holding necessary info to upload a file to a repository on the Hub. - - Args: - path_in_repo (`str`): - Relative filepath in the repo, for example: `"checkpoints/1fec34a/weights.bin"` - path_or_fileobj (`str`, `Path`, `bytes`, or `BinaryIO`): - Either: - - a path to a local file (as `str` or `pathlib.Path`) to upload - - a buffer of bytes (`bytes`) holding the content of the file to upload - - a "file object" (subclass of `io.BufferedIOBase`), typically obtained - with `open(path, "rb")`. It must support `seek()` and `tell()` methods. - - Raises: - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If `path_or_fileobj` is not one of `str`, `Path`, `bytes` or `io.BufferedIOBase`. - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If `path_or_fileobj` is a `str` or `Path` but not a path to an existing file. - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If `path_or_fileobj` is a `io.BufferedIOBase` but it doesn't support both - `seek()` and `tell()`. - """ - - path_in_repo: str - path_or_fileobj: Union[str, Path, bytes, BinaryIO] - upload_info: UploadInfo = field(init=False, repr=False) - - # Internal attributes - - # set to "lfs" or "regular" once known - _upload_mode: Optional[UploadMode] = field(init=False, repr=False, default=None) - - # set to True if .gitignore rules prevent the file from being uploaded as LFS - # (server-side check) - _should_ignore: Optional[bool] = field(init=False, repr=False, default=None) - - # set to the remote OID of the file if it has already been uploaded - # useful to determine if a commit will be empty or not - _remote_oid: Optional[str] = field(init=False, repr=False, default=None) - - # set to True once the file has been uploaded as LFS - _is_uploaded: bool = field(init=False, repr=False, default=False) - - # set to True once the file has been committed - _is_committed: bool = field(init=False, repr=False, default=False) - - def __post_init__(self) -> None: - """Validates `path_or_fileobj` and compute `upload_info`.""" - self.path_in_repo = _validate_path_in_repo(self.path_in_repo) - - # Validate `path_or_fileobj` value - if isinstance(self.path_or_fileobj, Path): - self.path_or_fileobj = str(self.path_or_fileobj) - if isinstance(self.path_or_fileobj, str): - path_or_fileobj = os.path.normpath(os.path.expanduser(self.path_or_fileobj)) - if not os.path.isfile(path_or_fileobj): - raise ValueError(f"Provided path: '{path_or_fileobj}' is not a file on the local file system") - elif not isinstance(self.path_or_fileobj, (io.BufferedIOBase, bytes)): - # ^^ Inspired from: https://stackoverflow.com/questions/44584829/how-to-determine-if-file-is-opened-in-binary-or-text-mode - raise ValueError( - "path_or_fileobj must be either an instance of str, bytes or" - " io.BufferedIOBase. If you passed a file-like object, make sure it is" - " in binary mode." - ) - if isinstance(self.path_or_fileobj, io.BufferedIOBase): - try: - self.path_or_fileobj.tell() - self.path_or_fileobj.seek(0, os.SEEK_CUR) - except (OSError, AttributeError) as exc: - raise ValueError( - "path_or_fileobj is a file-like object but does not implement seek() and tell()" - ) from exc - - # Compute "upload_info" attribute - if isinstance(self.path_or_fileobj, str): - self.upload_info = UploadInfo.from_path(self.path_or_fileobj) - elif isinstance(self.path_or_fileobj, bytes): - self.upload_info = UploadInfo.from_bytes(self.path_or_fileobj) - else: - self.upload_info = UploadInfo.from_fileobj(self.path_or_fileobj) - - @contextmanager - def as_file(self, with_tqdm: bool = False) -> Iterator[BinaryIO]: - """ - A context manager that yields a file-like object allowing to read the underlying - data behind `path_or_fileobj`. - - Args: - with_tqdm (`bool`, *optional*, defaults to `False`): - If True, iterating over the file object will display a progress bar. Only - works if the file-like object is a path to a file. Pure bytes and buffers - are not supported. - - Example: - - ```python - >>> operation = CommitOperationAdd( - ... path_in_repo="remote/dir/weights.h5", - ... path_or_fileobj="./local/weights.h5", - ... ) - CommitOperationAdd(path_in_repo='remote/dir/weights.h5', path_or_fileobj='./local/weights.h5') - - >>> with operation.as_file() as file: - ... content = file.read() - - >>> with operation.as_file(with_tqdm=True) as file: - ... while True: - ... data = file.read(1024) - ... if not data: - ... break - config.json: 100%|█████████████████████████| 8.19k/8.19k [00:02<00:00, 3.72kB/s] - - >>> with operation.as_file(with_tqdm=True) as file: - ... httpx.put(..., data=file) - config.json: 100%|█████████████████████████| 8.19k/8.19k [00:02<00:00, 3.72kB/s] - ``` - """ - if isinstance(self.path_or_fileobj, str) or isinstance(self.path_or_fileobj, Path): - if with_tqdm: - with tqdm_stream_file(self.path_or_fileobj) as file: - yield file - else: - with open(self.path_or_fileobj, "rb") as file: - yield file - elif isinstance(self.path_or_fileobj, bytes): - yield io.BytesIO(self.path_or_fileobj) - elif isinstance(self.path_or_fileobj, io.BufferedIOBase): - prev_pos = self.path_or_fileobj.tell() - yield self.path_or_fileobj - self.path_or_fileobj.seek(prev_pos, io.SEEK_SET) - - def b64content(self) -> bytes: - """ - The base64-encoded content of `path_or_fileobj` - - Returns: `bytes` - """ - with self.as_file() as file: - return base64.b64encode(file.read()) - - @property - def _local_oid(self) -> Optional[str]: - """Return the OID of the local file. - - This OID is then compared to `self._remote_oid` to check if the file has changed compared to the remote one. - If the file did not change, we won't upload it again to prevent empty commits. - - For LFS files, the OID corresponds to the SHA256 of the file content (used a LFS ref). - For regular files, the OID corresponds to the SHA1 of the file content. - Note: this is slightly different to git OID computation since the oid of an LFS file is usually the git-SHA1 of the - pointer file content (not the actual file content). However, using the SHA256 is enough to detect changes - and more convenient client-side. - """ - if self._upload_mode is None: - return None - elif self._upload_mode == "lfs": - return self.upload_info.sha256.hex() - else: - # Regular file => compute sha1 - # => no need to read by chunk since the file is guaranteed to be <=5MB. - with self.as_file() as file: - return sha.git_hash(file.read()) - - -def _validate_path_in_repo(path_in_repo: str) -> str: - # Validate `path_in_repo` value to prevent a server-side issue - if path_in_repo.startswith("/"): - path_in_repo = path_in_repo[1:] - if path_in_repo == "." or path_in_repo == ".." or path_in_repo.startswith("../"): - raise ValueError(f"Invalid `path_in_repo` in CommitOperation: '{path_in_repo}'") - if path_in_repo.startswith("./"): - path_in_repo = path_in_repo[2:] - for forbidden in FORBIDDEN_FOLDERS: - if any(part == forbidden for part in path_in_repo.split("/")): - raise ValueError( - f"Invalid `path_in_repo` in CommitOperation: cannot update files under a '{forbidden}/' folder (path:" - f" '{path_in_repo}')." - ) - return path_in_repo - - -CommitOperation = Union[CommitOperationAdd, CommitOperationCopy, CommitOperationDelete] - - -def _warn_on_overwriting_operations(operations: list[CommitOperation]) -> None: - """ - Warn user when a list of operations is expected to overwrite itself in a single - commit. - - Rules: - - If a filepath is updated by multiple `CommitOperationAdd` operations, a warning - message is triggered. - - If a filepath is updated at least once by a `CommitOperationAdd` and then deleted - by a `CommitOperationDelete`, a warning is triggered. - - If a `CommitOperationDelete` deletes a filepath that is then updated by a - `CommitOperationAdd`, no warning is triggered. This is usually useless (no need to - delete before upload) but can happen if a user deletes an entire folder and then - add new files to it. - """ - nb_additions_per_path: dict[str, int] = defaultdict(int) - for operation in operations: - path_in_repo = operation.path_in_repo - if isinstance(operation, CommitOperationAdd): - if nb_additions_per_path[path_in_repo] > 0: - warnings.warn( - "About to update multiple times the same file in the same commit:" - f" '{path_in_repo}'. This can cause undesired inconsistencies in" - " your repo." - ) - nb_additions_per_path[path_in_repo] += 1 - for parent in PurePosixPath(path_in_repo).parents: - # Also keep track of number of updated files per folder - # => warns if deleting a folder overwrite some contained files - nb_additions_per_path[str(parent)] += 1 - if isinstance(operation, CommitOperationDelete): - if nb_additions_per_path[str(PurePosixPath(path_in_repo))] > 0: - if operation.is_folder: - warnings.warn( - "About to delete a folder containing files that have just been" - f" updated within the same commit: '{path_in_repo}'. This can" - " cause undesired inconsistencies in your repo." - ) - else: - warnings.warn( - "About to delete a file that have just been updated within the" - f" same commit: '{path_in_repo}'. This can cause undesired" - " inconsistencies in your repo." - ) - - -@validate_hf_hub_args -def _upload_files( - *, - additions: list[CommitOperationAdd], - repo_type: str, - repo_id: str, - headers: dict[str, str], - endpoint: Optional[str] = None, - num_threads: int = 5, - revision: Optional[str] = None, - create_pr: Optional[bool] = None, -): - """ - Negotiates per-file transfer (LFS vs Xet) and uploads in batches. - """ - xet_additions: list[CommitOperationAdd] = [] - lfs_actions: list[dict[str, Any]] = [] - lfs_oid2addop: dict[str, CommitOperationAdd] = {} - - for chunk in chunk_iterable(additions, chunk_size=UPLOAD_BATCH_MAX_NUM_FILES): - chunk_list = [op for op in chunk] - - transfers: list[str] = ["basic", "multipart"] - has_buffered_io_data = any(isinstance(op.path_or_fileobj, io.BufferedIOBase) for op in chunk_list) - if is_xet_available(): - if not has_buffered_io_data: - transfers.append("xet") - else: - logger.warning( - "Uploading files as a binary IO buffer is not supported by Xet Storage. " - "Falling back to HTTP upload." - ) - - actions_chunk, errors_chunk, chosen_transfer = post_lfs_batch_info( - upload_infos=[op.upload_info for op in chunk_list], - repo_id=repo_id, - repo_type=repo_type, - revision=revision, - endpoint=endpoint, - headers=headers, - token=None, # already passed in 'headers' - transfers=transfers, - ) - if errors_chunk: - message = "\n".join( - [ - f"Encountered error for file with OID {err.get('oid')}: `{err.get('error', {}).get('message')}" - for err in errors_chunk - ] - ) - raise ValueError(f"LFS batch API returned errors:\n{message}") - - # If server returns a transfer we didn't offer (e.g "xet" while uploading from BytesIO), - # fall back to LFS for this chunk. - if chosen_transfer == "xet" and ("xet" in transfers): - xet_additions.extend(chunk_list) - else: - lfs_actions.extend(actions_chunk) - for op in chunk_list: - lfs_oid2addop[op.upload_info.sha256.hex()] = op - - if len(lfs_actions) > 0: - _upload_lfs_files( - actions=lfs_actions, - oid2addop=lfs_oid2addop, - headers=headers, - endpoint=endpoint, - num_threads=num_threads, - ) - - if len(xet_additions) > 0: - _upload_xet_files( - additions=xet_additions, - repo_type=repo_type, - repo_id=repo_id, - headers=headers, - endpoint=endpoint, - revision=revision, - create_pr=create_pr, - ) - - -@validate_hf_hub_args -def _upload_lfs_files( - *, - actions: list[dict[str, Any]], - oid2addop: dict[str, CommitOperationAdd], - headers: dict[str, str], - endpoint: Optional[str] = None, - num_threads: int = 5, -): - """ - Uploads the content of `additions` to the Hub using the large file storage protocol. - - Relevant external documentation: - - LFS Batch API: https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md - - Args: - actions (`list[dict[str, Any]]`): - LFS batch actions returned by the server. - oid2addop (`dict[str, CommitOperationAdd]`): - A dictionary mapping the OID of the file to the corresponding `CommitOperationAdd` object. - headers (`dict[str, str]`): - Headers to use for the request, including authorization headers and user agent. - endpoint (`str`, *optional*): - The endpoint to use for the request. Defaults to `constants.ENDPOINT`. - num_threads (`int`, *optional*): - The number of concurrent threads to use when uploading. Defaults to 5. - - Raises: - [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError) - If an upload failed for any reason - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`. - repo_id (`str`): - A namespace (user or an organization) and a repo name separated - by a `/`. - headers (`dict[str, str]`): - Headers to use for the request, including authorization headers and user agent. - num_threads (`int`, *optional*): - The number of concurrent threads to use when uploading. Defaults to 5. - revision (`str`, *optional*): - The git revision to upload to. - - Raises: - [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError) - If an upload failed for any reason - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If the server returns malformed responses - [`HfHubHTTPError`] - If the LFS batch endpoint returned an HTTP error. - """ - # Filter out files already present upstream - filtered_actions = [] - for action in actions: - if action.get("actions") is None: - logger.debug( - f"Content of file {oid2addop[action['oid']].path_in_repo} is already present upstream - skipping upload." - ) - else: - filtered_actions.append(action) - - # Upload according to server-provided actions - def _wrapped_lfs_upload(batch_action) -> None: - try: - operation = oid2addop[batch_action["oid"]] - lfs_upload(operation=operation, lfs_batch_action=batch_action, headers=headers, endpoint=endpoint) - except Exception as exc: - raise RuntimeError(f"Error while uploading '{operation.path_in_repo}' to the Hub.") from exc - - if len(filtered_actions) == 1: - logger.debug("Uploading 1 LFS file to the Hub") - _wrapped_lfs_upload(filtered_actions[0]) - else: - logger.debug( - f"Uploading {len(filtered_actions)} LFS files to the Hub using up to {num_threads} threads concurrently" - ) - thread_map( - _wrapped_lfs_upload, - filtered_actions, - desc=f"Upload {len(filtered_actions)} LFS files", - max_workers=num_threads, - tqdm_class=hf_tqdm, - ) - - -@validate_hf_hub_args -def _upload_xet_files( - *, - additions: list[CommitOperationAdd], - repo_type: str, - repo_id: str, - headers: dict[str, str], - endpoint: Optional[str] = None, - revision: Optional[str] = None, - create_pr: Optional[bool] = None, -): - """ - Uploads the content of `additions` to the Hub using the xet storage protocol. - This chunks the files and deduplicates the chunks before uploading them to xetcas storage. - - Args: - additions (`` of `CommitOperationAdd`): - The files to be uploaded. - repo_type (`str`): - Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`. - repo_id (`str`): - A namespace (user or an organization) and a repo name separated - by a `/`. - headers (`dict[str, str]`): - Headers to use for the request, including authorization headers and user agent. - endpoint: (`str`, *optional*): - The endpoint to use for the xetcas service. Defaults to `constants.ENDPOINT`. - revision (`str`, *optional*): - The git revision to upload to. - create_pr (`bool`, *optional*): - Whether or not to create a Pull Request with that commit. - - Raises: - [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError) - If an upload failed for any reason. - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If the server returns malformed responses or if the user is unauthorized to upload to xet storage. - [`HfHubHTTPError`] - If the LFS batch endpoint returned an HTTP error. - - **How it works:** - The file download system uses Xet storage, which is a content-addressable storage system that breaks files into chunks - for efficient storage and transfer. - - `hf_xet.upload_files` manages uploading files by: - - Taking a list of file paths to upload - - Breaking files into smaller chunks for efficient storage - - Avoiding duplicate storage by recognizing identical chunks across files - - Connecting to a storage server (CAS server) that manages these chunks - - The upload process works like this: - 1. Create a local folder at ~/.cache/huggingface/xet/chunk-cache to store file chunks for reuse. - 2. Process files in parallel (up to 8 files at once): - 2.1. Read the file content. - 2.2. Split the file content into smaller chunks based on content patterns: each chunk gets a unique ID based on what's in it. - 2.3. For each chunk: - - Check if it already exists in storage. - - Skip uploading chunks that already exist. - 2.4. Group chunks into larger blocks for efficient transfer. - 2.5. Upload these blocks to the storage server. - 2.6. Create and upload information about how the file is structured. - 3. Return reference files that contain information about the uploaded files, which can be used later to download them. - """ - if len(additions) == 0: - return - - # at this point, we know that hf_xet is installed - from hf_xet import upload_bytes, upload_files - - from .utils._xet_progress_reporting import XetProgressReporter - - try: - xet_connection_info = fetch_xet_connection_info_from_repo_info( - token_type=XetTokenType.WRITE, - repo_id=repo_id, - repo_type=repo_type, - revision=revision, - headers=headers, - endpoint=endpoint, - params={"create_pr": "1"} if create_pr else None, - ) - except HfHubHTTPError as e: - if e.response.status_code == 401: - raise XetAuthorizationError( - f"You are unauthorized to upload to xet storage for {repo_type}/{repo_id}. " - f"Please check that you have configured your access token with write access to the repo." - ) from e - raise - - xet_endpoint = xet_connection_info.endpoint - access_token_info = (xet_connection_info.access_token, xet_connection_info.expiration_unix_epoch) - - def token_refresher() -> tuple[str, int]: - new_xet_connection = fetch_xet_connection_info_from_repo_info( - token_type=XetTokenType.WRITE, - repo_id=repo_id, - repo_type=repo_type, - revision=revision, - headers=headers, - endpoint=endpoint, - params={"create_pr": "1"} if create_pr else None, - ) - if new_xet_connection is None: - raise XetRefreshTokenError("Failed to refresh xet token") - return new_xet_connection.access_token, new_xet_connection.expiration_unix_epoch - - if not are_progress_bars_disabled(): - progress = XetProgressReporter() - progress_callback = progress.update_progress - else: - progress, progress_callback = None, None - - try: - all_bytes_ops = [op for op in additions if isinstance(op.path_or_fileobj, bytes)] - all_paths_ops = [op for op in additions if isinstance(op.path_or_fileobj, (str, Path))] - - if len(all_paths_ops) > 0: - all_paths = [str(op.path_or_fileobj) for op in all_paths_ops] - upload_files( - all_paths, - xet_endpoint, - access_token_info, - token_refresher, - progress_callback, - repo_type, - ) - - if len(all_bytes_ops) > 0: - all_bytes = [op.path_or_fileobj for op in all_bytes_ops] - upload_bytes( - all_bytes, - xet_endpoint, - access_token_info, - token_refresher, - progress_callback, - repo_type, - ) - - finally: - if progress is not None: - progress.close(False) - - return - - -def _validate_preupload_info(preupload_info: dict): - files = preupload_info.get("files") - if not isinstance(files, list): - raise ValueError("preupload_info is improperly formatted") - for file_info in files: - if not ( - isinstance(file_info, dict) - and isinstance(file_info.get("path"), str) - and isinstance(file_info.get("uploadMode"), str) - and (file_info["uploadMode"] in ("lfs", "regular")) - ): - raise ValueError("preupload_info is improperly formatted:") - return preupload_info - - -@validate_hf_hub_args -def _fetch_upload_modes( - additions: Iterable[CommitOperationAdd], - repo_type: str, - repo_id: str, - headers: dict[str, str], - revision: str, - endpoint: Optional[str] = None, - create_pr: bool = False, - gitignore_content: Optional[str] = None, -) -> None: - """ - Requests the Hub "preupload" endpoint to determine whether each input file should be uploaded as a regular git blob, - as a git LFS blob, or as a XET file. Input `additions` are mutated in-place with the upload mode. - - Args: - additions (`Iterable` of :class:`CommitOperationAdd`): - Iterable of :class:`CommitOperationAdd` describing the files to - upload to the Hub. - repo_type (`str`): - Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`. - repo_id (`str`): - A namespace (user or an organization) and a repo name separated - by a `/`. - headers (`dict[str, str]`): - Headers to use for the request, including authorization headers and user agent. - revision (`str`): - The git revision to upload the files to. Can be any valid git revision. - gitignore_content (`str`, *optional*): - The content of the `.gitignore` file to know which files should be ignored. The order of priority - is to first check if `gitignore_content` is passed, then check if the `.gitignore` file is present - in the list of files to commit and finally default to the `.gitignore` file already hosted on the Hub - (if any). - Raises: - [`~utils.HfHubHTTPError`] - If the Hub API returned an error. - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If the Hub API response is improperly formatted. - """ - endpoint = endpoint if endpoint is not None else constants.ENDPOINT - - # Fetch upload mode (LFS or regular) chunk by chunk. - upload_modes: dict[str, UploadMode] = {} - should_ignore_info: dict[str, bool] = {} - oid_info: dict[str, Optional[str]] = {} - - for chunk in chunk_iterable(additions, 256): - payload: dict = { - "files": [ - { - "path": op.path_in_repo, - "sample": base64.b64encode(op.upload_info.sample).decode("ascii"), - "size": op.upload_info.size, - } - for op in chunk - ] - } - if gitignore_content is not None: - payload["gitIgnore"] = gitignore_content - - resp = http_backoff( - "POST", - f"{endpoint}/api/{repo_type}s/{repo_id}/preupload/{revision}", - json=payload, - headers=headers, - params={"create_pr": "1"} if create_pr else None, - ) - hf_raise_for_status(resp) - preupload_info = _validate_preupload_info(resp.json()) - upload_modes.update(**{file["path"]: file["uploadMode"] for file in preupload_info["files"]}) - should_ignore_info.update(**{file["path"]: file["shouldIgnore"] for file in preupload_info["files"]}) - oid_info.update(**{file["path"]: file.get("oid") for file in preupload_info["files"]}) - - # Set upload mode for each addition operation - for addition in additions: - addition._upload_mode = upload_modes[addition.path_in_repo] - addition._should_ignore = should_ignore_info[addition.path_in_repo] - addition._remote_oid = oid_info[addition.path_in_repo] - - # Empty files cannot be uploaded as LFS (S3 would fail with a 501 Not Implemented) - # => empty files are uploaded as "regular" to still allow users to commit them. - for addition in additions: - if addition.upload_info.size == 0: - addition._upload_mode = "regular" - - -@validate_hf_hub_args -def _fetch_files_to_copy( - copies: Iterable[CommitOperationCopy], - repo_type: str, - repo_id: str, - headers: dict[str, str], - revision: str, - endpoint: Optional[str] = None, -) -> dict[tuple[str, Optional[str]], Union["RepoFile", bytes]]: - """ - Fetch information about the files to copy. - - For LFS files, we only need their metadata (file size and sha256) while for regular files - we need to download the raw content from the Hub. - - Args: - copies (`Iterable` of :class:`CommitOperationCopy`): - Iterable of :class:`CommitOperationCopy` describing the files to - copy on the Hub. - repo_type (`str`): - Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`. - repo_id (`str`): - A namespace (user or an organization) and a repo name separated - by a `/`. - headers (`dict[str, str]`): - Headers to use for the request, including authorization headers and user agent. - revision (`str`): - The git revision to upload the files to. Can be any valid git revision. - - Returns: `dict[tuple[str, Optional[str]], Union[RepoFile, bytes]]]` - Key is the file path and revision of the file to copy. - Value is the raw content as bytes (for regular files) or the file information as a RepoFile (for LFS files). - - Raises: - [`~utils.HfHubHTTPError`] - If the Hub API returned an error. - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If the Hub API response is improperly formatted. - """ - from .hf_api import HfApi, RepoFolder - - hf_api = HfApi(endpoint=endpoint, headers=headers) - files_to_copy: dict[tuple[str, Optional[str]], Union["RepoFile", bytes]] = {} - # Store (path, revision) -> oid mapping - oid_info: dict[tuple[str, Optional[str]], Optional[str]] = {} - # 1. Fetch OIDs for destination paths in batches. - dest_paths = [op.path_in_repo for op in copies] - for offset in range(0, len(dest_paths), FETCH_LFS_BATCH_SIZE): - dest_repo_files = hf_api.get_paths_info( - repo_id=repo_id, - paths=dest_paths[offset : offset + FETCH_LFS_BATCH_SIZE], - revision=revision, - repo_type=repo_type, - ) - for file in dest_repo_files: - if not isinstance(file, RepoFolder): - oid_info[(file.path, revision)] = file.blob_id - - # 2. Group by source revision and fetch source file info in batches. - for src_revision, operations in groupby(copies, key=lambda op: op.src_revision): - operations = list(operations) # type: ignore - src_paths = [op.src_path_in_repo for op in operations] - for offset in range(0, len(src_paths), FETCH_LFS_BATCH_SIZE): - src_repo_files = hf_api.get_paths_info( - repo_id=repo_id, - paths=src_paths[offset : offset + FETCH_LFS_BATCH_SIZE], - revision=src_revision or revision, - repo_type=repo_type, - ) - - for src_repo_file in src_repo_files: - if isinstance(src_repo_file, RepoFolder): - raise NotImplementedError("Copying a folder is not implemented.") - oid_info[(src_repo_file.path, src_revision)] = src_repo_file.blob_id - # If it's an LFS file, store the RepoFile object. Otherwise, download raw bytes. - if src_repo_file.lfs: - files_to_copy[(src_repo_file.path, src_revision)] = src_repo_file - else: - # TODO: (optimization) download regular files to copy concurrently - url = hf_hub_url( - endpoint=endpoint, - repo_type=repo_type, - repo_id=repo_id, - revision=src_revision or revision, - filename=src_repo_file.path, - ) - response = get_session().get(url, headers=headers) - hf_raise_for_status(response) - files_to_copy[(src_repo_file.path, src_revision)] = response.content - # 3. Ensure all operations found a corresponding file in the Hub - # and track src/dest OIDs for each operation. - for operation in operations: - if (operation.src_path_in_repo, src_revision) not in files_to_copy: - raise EntryNotFoundError( - f"Cannot copy {operation.src_path_in_repo} at revision " - f"{src_revision or revision}: file is missing on repo." - ) - operation._src_oid = oid_info.get((operation.src_path_in_repo, operation.src_revision)) - operation._dest_oid = oid_info.get((operation.path_in_repo, revision)) - return files_to_copy - - -def _prepare_commit_payload( - operations: Iterable[CommitOperation], - files_to_copy: dict[tuple[str, Optional[str]], Union["RepoFile", bytes]], - commit_message: str, - commit_description: Optional[str] = None, - parent_commit: Optional[str] = None, -) -> Iterable[dict[str, Any]]: - """ - Builds the payload to POST to the `/commit` API of the Hub. - - Payload is returned as an iterator so that it can be streamed as a ndjson in the - POST request. - - For more information, see: - - https://github.com/huggingface/huggingface_hub/issues/1085#issuecomment-1265208073 - - http://ndjson.org/ - """ - commit_description = commit_description if commit_description is not None else "" - - # 1. Send a header item with the commit metadata - header_value = {"summary": commit_message, "description": commit_description} - if parent_commit is not None: - header_value["parentCommit"] = parent_commit - yield {"key": "header", "value": header_value} - - nb_ignored_files = 0 - - # 2. Send operations, one per line - for operation in operations: - # Skip ignored files - if isinstance(operation, CommitOperationAdd) and operation._should_ignore: - logger.debug(f"Skipping file '{operation.path_in_repo}' in commit (ignored by gitignore file).") - nb_ignored_files += 1 - continue - - # 2.a. Case adding a regular file - if isinstance(operation, CommitOperationAdd) and operation._upload_mode == "regular": - yield { - "key": "file", - "value": { - "content": operation.b64content().decode(), - "path": operation.path_in_repo, - "encoding": "base64", - }, - } - # 2.b. Case adding an LFS file - elif isinstance(operation, CommitOperationAdd) and operation._upload_mode == "lfs": - yield { - "key": "lfsFile", - "value": { - "path": operation.path_in_repo, - "algo": "sha256", - "oid": operation.upload_info.sha256.hex(), - "size": operation.upload_info.size, - }, - } - # 2.c. Case deleting a file or folder - elif isinstance(operation, CommitOperationDelete): - yield { - "key": "deletedFolder" if operation.is_folder else "deletedFile", - "value": {"path": operation.path_in_repo}, - } - # 2.d. Case copying a file or folder - elif isinstance(operation, CommitOperationCopy): - file_to_copy = files_to_copy[(operation.src_path_in_repo, operation.src_revision)] - if isinstance(file_to_copy, bytes): - yield { - "key": "file", - "value": { - "content": base64.b64encode(file_to_copy).decode(), - "path": operation.path_in_repo, - "encoding": "base64", - }, - } - elif file_to_copy.lfs: - yield { - "key": "lfsFile", - "value": { - "path": operation.path_in_repo, - "algo": "sha256", - "oid": file_to_copy.lfs.sha256, - }, - } - else: - raise ValueError( - "Malformed files_to_copy (should be raw file content as bytes or RepoFile objects with LFS info." - ) - # 2.e. Never expected to happen - else: - raise ValueError( - f"Unknown operation to commit. Operation: {operation}. Upload mode:" - f" {getattr(operation, '_upload_mode', None)}" - ) - - if nb_ignored_files > 0: - logger.info(f"Skipped {nb_ignored_files} file(s) in commit (ignored by gitignore file).") diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_commit_scheduler.py b/venv/lib/python3.10/site-packages/huggingface_hub/_commit_scheduler.py deleted file mode 100644 index 497c9a0be52d23d1d8bf4fe36f3dcfb54e7d665f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_commit_scheduler.py +++ /dev/null @@ -1,353 +0,0 @@ -import atexit -import logging -import os -import time -from concurrent.futures import Future -from dataclasses import dataclass -from io import SEEK_END, SEEK_SET, BytesIO -from pathlib import Path -from threading import Lock, Thread -from typing import Optional, Union - -from .hf_api import DEFAULT_IGNORE_PATTERNS, CommitInfo, CommitOperationAdd, HfApi -from .utils import filter_repo_objects - - -logger = logging.getLogger(__name__) - - -@dataclass(frozen=True) -class _FileToUpload: - """Temporary dataclass to store info about files to upload. Not meant to be used directly.""" - - local_path: Path - path_in_repo: str - size_limit: int - last_modified: float - - -class CommitScheduler: - """ - Scheduler to upload a local folder to the Hub at regular intervals (e.g. push to hub every 5 minutes). - - The recommended way to use the scheduler is to use it as a context manager. This ensures that the scheduler is - properly stopped and the last commit is triggered when the script ends. The scheduler can also be stopped manually - with the `stop` method. Checkout the [upload guide](https://huggingface.co/docs/huggingface_hub/guides/upload#scheduled-uploads) - to learn more about how to use it. - - Args: - repo_id (`str`): - The id of the repo to commit to. - folder_path (`str` or `Path`): - Path to the local folder to upload regularly. - every (`int` or `float`, *optional*): - The number of minutes between each commit. Defaults to 5 minutes. - path_in_repo (`str`, *optional*): - Relative path of the directory in the repo, for example: `"checkpoints/"`. Defaults to the root folder - of the repository. - repo_type (`str`, *optional*): - The type of the repo to commit to. Defaults to `model`. - revision (`str`, *optional*): - The revision of the repo to commit to. Defaults to `main`. - private (`bool`, *optional*): - Whether to make the repo private. If `None` (default), the repo will be public unless the organization's default is private. This value is ignored if the repo already exists. - token (`str`, *optional*): - The token to use to commit to the repo. Defaults to the token saved on the machine. - allow_patterns (`list[str]` or `str`, *optional*): - If provided, only files matching at least one pattern are uploaded. - ignore_patterns (`list[str]` or `str`, *optional*): - If provided, files matching any of the patterns are not uploaded. - squash_history (`bool`, *optional*): - Whether to squash the history of the repo after each commit. Defaults to `False`. Squashing commits is - useful to avoid degraded performances on the repo when it grows too large. - hf_api (`HfApi`, *optional*): - The [`HfApi`] client to use to commit to the Hub. Can be set with custom settings (user agent, token,...). - - Example: - ```py - >>> from pathlib import Path - >>> from huggingface_hub import CommitScheduler - - # Scheduler uploads every 10 minutes - >>> csv_path = Path("watched_folder/data.csv") - >>> CommitScheduler(repo_id="test_scheduler", repo_type="dataset", folder_path=csv_path.parent, every=10) - - >>> with csv_path.open("a") as f: - ... f.write("first line") - - # Some time later (...) - >>> with csv_path.open("a") as f: - ... f.write("second line") - ``` - - Example using a context manager: - ```py - >>> from pathlib import Path - >>> from huggingface_hub import CommitScheduler - - >>> with CommitScheduler(repo_id="test_scheduler", repo_type="dataset", folder_path="watched_folder", every=10) as scheduler: - ... csv_path = Path("watched_folder/data.csv") - ... with csv_path.open("a") as f: - ... f.write("first line") - ... (...) - ... with csv_path.open("a") as f: - ... f.write("second line") - - # Scheduler is now stopped and last commit have been triggered - ``` - """ - - def __init__( - self, - *, - repo_id: str, - folder_path: Union[str, Path], - every: Union[int, float] = 5, - path_in_repo: Optional[str] = None, - repo_type: Optional[str] = None, - revision: Optional[str] = None, - private: Optional[bool] = None, - token: Optional[str] = None, - allow_patterns: Optional[Union[list[str], str]] = None, - ignore_patterns: Optional[Union[list[str], str]] = None, - squash_history: bool = False, - hf_api: Optional["HfApi"] = None, - ) -> None: - self.api = hf_api or HfApi(token=token) - - # Folder - self.folder_path = Path(folder_path).expanduser().resolve() - self.path_in_repo = path_in_repo or "" - self.allow_patterns = allow_patterns - - if ignore_patterns is None: - ignore_patterns = [] - elif isinstance(ignore_patterns, str): - ignore_patterns = [ignore_patterns] - self.ignore_patterns = ignore_patterns + DEFAULT_IGNORE_PATTERNS - - if self.folder_path.is_file(): - raise ValueError(f"'folder_path' must be a directory, not a file: '{self.folder_path}'.") - self.folder_path.mkdir(parents=True, exist_ok=True) - - # Repository - repo_url = self.api.create_repo(repo_id=repo_id, private=private, repo_type=repo_type, exist_ok=True) - self.repo_id = repo_url.repo_id - self.repo_type = repo_type - self.revision = revision - self.token = token - - # Keep track of already uploaded files - self.last_uploaded: dict[Path, float] = {} # key is local path, value is timestamp - - # Scheduler - if not every > 0: - raise ValueError(f"'every' must be a positive integer, not '{every}'.") - self.lock = Lock() - self.every = every - self.squash_history = squash_history - - logger.info(f"Scheduled job to push '{self.folder_path}' to '{self.repo_id}' every {self.every} minutes.") - self._scheduler_thread = Thread(target=self._run_scheduler, daemon=True) - self._scheduler_thread.start() - atexit.register(self._push_to_hub) - - self.__stopped = False - - def stop(self) -> None: - """Stop the scheduler. - - A stopped scheduler cannot be restarted. Mostly for tests purposes. - """ - self.__stopped = True - - def __enter__(self) -> "CommitScheduler": - return self - - def __exit__(self, exc_type, exc_value, traceback) -> None: - # Upload last changes before exiting - self.trigger().result() - self.stop() - return - - def _run_scheduler(self) -> None: - """Dumb thread waiting between each scheduled push to Hub.""" - while True: - self.last_future = self.trigger() - time.sleep(self.every * 60) - if self.__stopped: - break - - def trigger(self) -> Future: - """Trigger a `push_to_hub` and return a future. - - This method is automatically called every `every` minutes. You can also call it manually to trigger a commit - immediately, without waiting for the next scheduled commit. - """ - return self.api.run_as_future(self._push_to_hub) - - def _push_to_hub(self) -> Optional[CommitInfo]: - if self.__stopped: # If stopped, already scheduled commits are ignored - return None - - logger.info("(Background) scheduled commit triggered.") - try: - value = self.push_to_hub() - if self.squash_history: - logger.info("(Background) squashing repo history.") - self.api.super_squash_history(repo_id=self.repo_id, repo_type=self.repo_type, branch=self.revision) - return value - except Exception as e: - logger.error(f"Error while pushing to Hub: {e}") # Depending on the setup, error might be silenced - raise - - def push_to_hub(self) -> Optional[CommitInfo]: - """ - Push folder to the Hub and return the commit info. - - > [!WARNING] - > This method is not meant to be called directly. It is run in the background by the scheduler, respecting a - > queue mechanism to avoid concurrent commits. Making a direct call to the method might lead to concurrency - > issues. - - The default behavior of `push_to_hub` is to assume an append-only folder. It lists all files in the folder and - uploads only changed files. If no changes are found, the method returns without committing anything. If you want - to change this behavior, you can inherit from [`CommitScheduler`] and override this method. This can be useful - for example to compress data together in a single file before committing. For more details and examples, check - out our [integration guide](https://huggingface.co/docs/huggingface_hub/main/en/guides/upload#scheduled-uploads). - """ - # Check files to upload (with lock) - with self.lock: - logger.debug("Listing files to upload for scheduled commit.") - - # List files from folder (taken from `_prepare_upload_folder_additions`) - relpath_to_abspath = { - path.relative_to(self.folder_path).as_posix(): path - for path in sorted(self.folder_path.glob("**/*")) # sorted to be deterministic - if path.is_file() - } - prefix = f"{self.path_in_repo.strip('/')}/" if self.path_in_repo else "" - - # Filter with pattern + filter out unchanged files + retrieve current file size - files_to_upload: list[_FileToUpload] = [] - for relpath in filter_repo_objects( - relpath_to_abspath.keys(), allow_patterns=self.allow_patterns, ignore_patterns=self.ignore_patterns - ): - local_path = relpath_to_abspath[relpath] - stat = local_path.stat() - if self.last_uploaded.get(local_path) is None or self.last_uploaded[local_path] != stat.st_mtime: - files_to_upload.append( - _FileToUpload( - local_path=local_path, - path_in_repo=prefix + relpath, - size_limit=stat.st_size, - last_modified=stat.st_mtime, - ) - ) - - # Return if nothing to upload - if len(files_to_upload) == 0: - logger.debug("Dropping schedule commit: no changed file to upload.") - return None - - # Convert `_FileToUpload` as `CommitOperationAdd` (=> compute file shas + limit to file size) - logger.debug("Removing unchanged files since previous scheduled commit.") - add_operations = [ - CommitOperationAdd( - # Cap the file to its current size, even if the user append data to it while a scheduled commit is happening - path_or_fileobj=PartialFileIO(file_to_upload.local_path, size_limit=file_to_upload.size_limit), - path_in_repo=file_to_upload.path_in_repo, - ) - for file_to_upload in files_to_upload - ] - - # Upload files (append mode expected - no need for lock) - logger.debug("Uploading files for scheduled commit.") - commit_info = self.api.create_commit( - repo_id=self.repo_id, - repo_type=self.repo_type, - operations=add_operations, - commit_message="Scheduled Commit", - revision=self.revision, - ) - - # Successful commit: keep track of the latest "last_modified" for each file - for file in files_to_upload: - self.last_uploaded[file.local_path] = file.last_modified - return commit_info - - -class PartialFileIO(BytesIO): - """A file-like object that reads only the first part of a file. - - Useful to upload a file to the Hub when the user might still be appending data to it. Only the first part of the - file is uploaded (i.e. the part that was available when the filesystem was first scanned). - - In practice, only used internally by the CommitScheduler to regularly push a folder to the Hub with minimal - disturbance for the user. The object is passed to `CommitOperationAdd`. - - Only supports `read`, `tell` and `seek` methods. - - Args: - file_path (`str` or `Path`): - Path to the file to read. - size_limit (`int`): - The maximum number of bytes to read from the file. If the file is larger than this, only the first part - will be read (and uploaded). - """ - - def __init__(self, file_path: Union[str, Path], size_limit: int) -> None: - self._file_path = Path(file_path) - self._file = self._file_path.open("rb") - self._size_limit = min(size_limit, os.fstat(self._file.fileno()).st_size) - - def __del__(self) -> None: - self._file.close() - return super().__del__() - - def __repr__(self) -> str: - return f"" - - def __len__(self) -> int: - return self._size_limit - - def __getattribute__(self, name: str): - if name.startswith("_") or name in ("read", "tell", "seek", "fileno"): # only 4 public methods supported - return super().__getattribute__(name) - raise NotImplementedError(f"PartialFileIO does not support '{name}'.") - - def fileno(self): - raise AttributeError("PartialFileIO does not have a fileno.") - - def tell(self) -> int: - """Return the current file position.""" - return self._file.tell() - - def seek(self, __offset: int, __whence: int = SEEK_SET) -> int: - """Change the stream position to the given offset. - - Behavior is the same as a regular file, except that the position is capped to the size limit. - """ - if __whence == SEEK_END: - # SEEK_END => set from the truncated end - __offset = len(self) + __offset - __whence = SEEK_SET - - pos = self._file.seek(__offset, __whence) - if pos > self._size_limit: - return self._file.seek(self._size_limit) - return pos - - def read(self, __size: Optional[int] = -1) -> bytes: - """Read at most `__size` bytes from the file. - - Behavior is the same as a regular file, except that it is capped to the size limit. - """ - current = self._file.tell() - if __size is None or __size < 0: - # Read until file limit - truncated_size = self._size_limit - current - else: - # Read until file limit or __size - truncated_size = min(__size, self._size_limit - current) - return self._file.read(truncated_size) diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_eval_results.py b/venv/lib/python3.10/site-packages/huggingface_hub/_eval_results.py deleted file mode 100644 index b0b753693cc8953d5c4e2128c7b56880598ff2f5..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_eval_results.py +++ /dev/null @@ -1,211 +0,0 @@ -"""Evaluation results utilities for the `.eval_results/*.yaml` format. - -See https://huggingface.co/docs/hub/eval-results for more details. -Specifications are available at https://github.com/huggingface/hub-docs/blob/main/eval_results.yaml. -""" - -from dataclasses import dataclass -from typing import Any, Optional - - -@dataclass -class EvalResultEntry: - """ - Evaluation result entry for the `.eval_results/*.yaml` format. - - Represents evaluation scores stored in model repos that automatically appear on - the model page and the benchmark dataset's leaderboard. - - For the legacy `model-index` format in `README.md`, use [`EvalResult`] instead. - - See https://huggingface.co/docs/hub/eval-results for more details. - - Args: - dataset_id (`str`): - Benchmark dataset ID from the Hub. Example: "cais/hle", "Idavidrein/gpqa". - task_id (`str`): - Task identifier within the benchmark. Example: "gpqa_diamond". - value (`Any`): - The metric value. Example: 20.90. - dataset_revision (`str`, *optional*): - Git SHA of the benchmark dataset. - verify_token (`str`, *optional*): - A signature that can be used to prove that evaluation is provably auditable and reproducible. - date (`str`, *optional*): - When the evaluation was run (ISO-8601 datetime). Defaults to git commit time. - source_url (`str`, *optional*): - Link to the evaluation source (e.g., https://huggingface.co/spaces/SaylorTwift/smollm3-mmlu-pro). Required if `source_name`, `source_user`, or `source_org` is provided. - source_name (`str`, *optional*): - Display name for the source. Example: "Eval Logs". - source_user (`str`, *optional*): - HF user name for attribution. Example: "celinah". - source_org (`str`, *optional*): - HF org name for attribution. Example: "cais". - notes (`str`, *optional*): - Details about the evaluation setup. Example: "tools", "no-tools", "chain-of-thought". - - Example: - ```python - >>> from huggingface_hub import EvalResultEntry - >>> # Minimal example with required fields only - >>> result = EvalResultEntry( - ... dataset_id="Idavidrein/gpqa", - ... task_id="gpqa_diamond", - ... value=0.412, - ... ) - >>> # Full example with all fields - >>> result = EvalResultEntry( - ... dataset_id="cais/hle", - ... task_id="default", - ... value=20.90, - ... dataset_revision="5503434ddd753f426f4b38109466949a1217c2bb", - ... verify_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - ... date="2025-01-15T10:30:00Z", - ... source_url="https://huggingface.co/datasets/cais/hle", - ... source_name="CAIS HLE", - ... source_org="cais", - ... notes="no-tools", - ... ) - - ``` - """ - - dataset_id: str - task_id: str - value: Any - dataset_revision: Optional[str] = None - verify_token: Optional[str] = None - date: Optional[str] = None - source_url: Optional[str] = None - source_name: Optional[str] = None - source_user: Optional[str] = None - source_org: Optional[str] = None - notes: Optional[str] = None - - def __post_init__(self) -> None: - if ( - self.source_name is not None or self.source_user is not None or self.source_org is not None - ) and self.source_url is None: - raise ValueError( - "If `source_name`, `source_user`, or `source_org` is provided, `source_url` must also be provided." - ) - - -def eval_result_entries_to_yaml(entries: list[EvalResultEntry]) -> list[dict[str, Any]]: - """Convert a list of [`EvalResultEntry`] objects to a YAML-serializable list of dicts. - - This produces the format expected in `.eval_results/*.yaml` files. - - Args: - entries (`list[EvalResultEntry]`): - List of evaluation result entries to serialize. - - Returns: - `list[dict[str, Any]]`: A list of dictionaries ready to be dumped to YAML. - - Example: - ```python - >>> from huggingface_hub import EvalResultEntry, eval_result_entries_to_yaml - >>> entries = [ - ... EvalResultEntry(dataset_id="cais/hle", task_id="default", value=20.90), - ... EvalResultEntry(dataset_id="Idavidrein/gpqa", task_id="gpqa_diamond", value=0.412), - ... ] - >>> yaml_data = eval_result_entries_to_yaml(entries) - >>> yaml_data[0] - {'dataset': {'id': 'cais/hle', 'task_id': 'default'}, 'value': 20.9} - - ``` - - To upload eval results to the Hub: - ```python - >>> import yaml - >>> from huggingface_hub import upload_file, EvalResultEntry, eval_result_entries_to_yaml - >>> entries = [ - ... EvalResultEntry(dataset_id="cais/hle", task_id="default", value=20.90), - ... ] - >>> yaml_content = yaml.dump(eval_result_entries_to_yaml(entries)) - >>> upload_file( - ... path_or_fileobj=yaml_content.encode(), - ... path_in_repo=".eval_results/hle.yaml", - ... repo_id="your-username/your-model", - ... ) - - ``` - """ - result = [] - for entry in entries: - # build the dataset object - dataset: dict[str, Any] = {"id": entry.dataset_id, "task_id": entry.task_id} - if entry.dataset_revision is not None: - dataset["revision"] = entry.dataset_revision - - data: dict[str, Any] = {"dataset": dataset, "value": entry.value} - if entry.verify_token is not None: - data["verifyToken"] = entry.verify_token - if entry.date is not None: - data["date"] = entry.date - # build the source object - if entry.source_url is not None: - source: dict[str, Any] = {"url": entry.source_url} - if entry.source_name is not None: - source["name"] = entry.source_name - if entry.source_user is not None: - source["user"] = entry.source_user - if entry.source_org is not None: - source["org"] = entry.source_org - data["source"] = source - if entry.notes is not None: - data["notes"] = entry.notes - - result.append(data) - return result - - -def parse_eval_result_entries(data: list[dict[str, Any]]) -> list[EvalResultEntry]: - """Parse a list of dicts into [`EvalResultEntry`] objects. - - This parses the `.eval_results/*.yaml` format. For the legacy `model-index` format, - use [`model_index_to_eval_results`] instead. - - Args: - data (`list[dict[str, Any]]`): - A list of dictionaries (e.g., parsed from YAML or API response). - - Returns: - `list[EvalResultEntry]`: A list of evaluation result entry objects. - - Example: - ```python - >>> from huggingface_hub import parse_eval_result_entries - >>> data = [ - ... {"dataset": {"id": "cais/hle", "task_id": "default"}, "value": 20.90}, - ... {"dataset": {"id": "Idavidrein/gpqa", "task_id": "gpqa_diamond"}, "value": 0.412}, - ... ] - >>> entries = parse_eval_result_entries(data) - >>> entries[0].dataset_id - 'cais/hle' - >>> entries[0].value - 20.9 - - ``` - """ - entries = [] - for item in data: - entry_data = item.get("data", item) - dataset = entry_data.get("dataset", {}) - source = entry_data.get("source", {}) - entry = EvalResultEntry( - dataset_id=dataset["id"], - value=entry_data["value"], - task_id=dataset["task_id"], - dataset_revision=dataset.get("revision"), - verify_token=entry_data.get("verifyToken"), - date=entry_data.get("date"), - source_url=source.get("url") if source else None, - source_name=source.get("name") if source else None, - source_user=source.get("user") if source else None, - source_org=source.get("org") if source else None, - notes=entry_data.get("notes"), - ) - entries.append(entry) - return entries diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_inference_endpoints.py b/venv/lib/python3.10/site-packages/huggingface_hub/_inference_endpoints.py deleted file mode 100644 index 1a680850c4aa8856e43e91174ee47f75e3dc5341..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_inference_endpoints.py +++ /dev/null @@ -1,418 +0,0 @@ -import time -from dataclasses import dataclass, field -from datetime import datetime -from enum import Enum -from typing import TYPE_CHECKING, Optional, Union - -from huggingface_hub.errors import InferenceEndpointError, InferenceEndpointTimeoutError - -from .utils import get_session, logging, parse_datetime - - -if TYPE_CHECKING: - from .hf_api import HfApi - from .inference._client import InferenceClient - from .inference._generated._async_client import AsyncInferenceClient - -logger = logging.get_logger(__name__) - - -class InferenceEndpointStatus(str, Enum): - PENDING = "pending" - INITIALIZING = "initializing" - UPDATING = "updating" - UPDATE_FAILED = "updateFailed" - RUNNING = "running" - PAUSED = "paused" - FAILED = "failed" - SCALED_TO_ZERO = "scaledToZero" - - -class InferenceEndpointType(str, Enum): - PUBlIC = "public" - PROTECTED = "protected" - PRIVATE = "private" - - -class InferenceEndpointScalingMetric(str, Enum): - PENDING_REQUESTS = "pendingRequests" - HARDWARE_USAGE = "hardwareUsage" - - -@dataclass -class InferenceEndpoint: - """ - Contains information about a deployed Inference Endpoint. - - Args: - name (`str`): - The unique name of the Inference Endpoint. - namespace (`str`): - The namespace where the Inference Endpoint is located. - repository (`str`): - The name of the model repository deployed on this Inference Endpoint. - status ([`InferenceEndpointStatus`]): - The current status of the Inference Endpoint. - url (`str`, *optional*): - The URL of the Inference Endpoint, if available. Only a deployed Inference Endpoint will have a URL. - framework (`str`): - The machine learning framework used for the model. - revision (`str`): - The specific model revision deployed on the Inference Endpoint. - task (`str`): - The task associated with the deployed model. - created_at (`datetime.datetime`): - The timestamp when the Inference Endpoint was created. - updated_at (`datetime.datetime`): - The timestamp of the last update of the Inference Endpoint. - type ([`InferenceEndpointType`]): - The type of the Inference Endpoint (public, protected, private). - raw (`dict`): - The raw dictionary data returned from the API. - token (`str` or `bool`, *optional*): - Authentication token for the Inference Endpoint, if set when requesting the API. Will default to the - locally saved token if not provided. Pass `token=False` if you don't want to send your token to the server. - - Example: - ```python - >>> from huggingface_hub import get_inference_endpoint - >>> endpoint = get_inference_endpoint("my-text-to-image") - >>> endpoint - InferenceEndpoint(name='my-text-to-image', ...) - - # Get status - >>> endpoint.status - 'running' - >>> endpoint.url - 'https://my-text-to-image.region.vendor.endpoints.huggingface.cloud' - - # Run inference - >>> endpoint.client.text_to_image(...) - - # Pause endpoint to save $$$ - >>> endpoint.pause() - - # ... - # Resume and wait for deployment - >>> endpoint.resume() - >>> endpoint.wait() - >>> endpoint.client.text_to_image(...) - ``` - """ - - # Field in __repr__ - name: str = field(init=False) - namespace: str - repository: str = field(init=False) - status: InferenceEndpointStatus = field(init=False) - health_route: str = field(init=False) - url: Optional[str] = field(init=False) - - # Other fields - framework: str = field(repr=False, init=False) - revision: str = field(repr=False, init=False) - task: str = field(repr=False, init=False) - created_at: datetime = field(repr=False, init=False) - updated_at: datetime = field(repr=False, init=False) - type: InferenceEndpointType = field(repr=False, init=False) - - # Raw dict from the API - raw: dict = field(repr=False) - - # Internal fields - _token: Union[str, bool, None] = field(repr=False, compare=False) - _api: "HfApi" = field(repr=False, compare=False) - - @classmethod - def from_raw( - cls, raw: dict, namespace: str, token: Union[str, bool, None] = None, api: Optional["HfApi"] = None - ) -> "InferenceEndpoint": - """Initialize object from raw dictionary.""" - if api is None: - from .hf_api import HfApi - - api = HfApi() - if token is None: - token = api.token - - # All other fields are populated in __post_init__ - return cls(raw=raw, namespace=namespace, _token=token, _api=api) - - def __post_init__(self) -> None: - """Populate fields from raw dictionary.""" - self._populate_from_raw() - - @property - def client(self) -> "InferenceClient": - """Returns a client to make predictions on this Inference Endpoint. - - Returns: - [`InferenceClient`]: an inference client pointing to the deployed endpoint. - - Raises: - [`InferenceEndpointError`]: If the Inference Endpoint is not yet deployed. - """ - if self.url is None: - raise InferenceEndpointError( - "Cannot create a client for this Inference Endpoint as it is not yet deployed. " - "Please wait for the Inference Endpoint to be deployed using `endpoint.wait()` and try again." - ) - from .inference._client import InferenceClient - - return InferenceClient( - model=self.url, - token=self._token, # type: ignore[arg-type] # boolean token shouldn't be possible. In practice it's ok. - ) - - @property - def async_client(self) -> "AsyncInferenceClient": - """Returns a client to make predictions on this Inference Endpoint. - - Returns: - [`AsyncInferenceClient`]: an asyncio-compatible inference client pointing to the deployed endpoint. - - Raises: - [`InferenceEndpointError`]: If the Inference Endpoint is not yet deployed. - """ - if self.url is None: - raise InferenceEndpointError( - "Cannot create a client for this Inference Endpoint as it is not yet deployed. " - "Please wait for the Inference Endpoint to be deployed using `endpoint.wait()` and try again." - ) - from .inference._generated._async_client import AsyncInferenceClient - - return AsyncInferenceClient( - model=self.url, - token=self._token, # type: ignore[arg-type] # boolean token shouldn't be possible. In practice it's ok. - ) - - def wait(self, timeout: Optional[int] = None, refresh_every: int = 5) -> "InferenceEndpoint": - """Wait for the Inference Endpoint to be deployed. - - Information from the server will be fetched every 1s. If the Inference Endpoint is not deployed after `timeout` - seconds, a [`InferenceEndpointTimeoutError`] will be raised. The [`InferenceEndpoint`] will be mutated in place with the latest - data. - - Args: - timeout (`int`, *optional*): - The maximum time to wait for the Inference Endpoint to be deployed, in seconds. If `None`, will wait - indefinitely. - refresh_every (`int`, *optional*): - The time to wait between each fetch of the Inference Endpoint status, in seconds. Defaults to 5s. - - Returns: - [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data. - - Raises: - [`InferenceEndpointError`] - If the Inference Endpoint ended up in a failed state. - [`InferenceEndpointTimeoutError`] - If the Inference Endpoint is not deployed after `timeout` seconds. - """ - if timeout is not None and timeout < 0: - raise ValueError("`timeout` cannot be negative.") - if refresh_every <= 0: - raise ValueError("`refresh_every` must be positive.") - - start = time.time() - while True: - if self.status == InferenceEndpointStatus.FAILED: - raise InferenceEndpointError( - f"Inference Endpoint {self.name} failed to deploy. Please check the logs for more information." - ) - if self.status == InferenceEndpointStatus.UPDATE_FAILED: - raise InferenceEndpointError( - f"Inference Endpoint {self.name} failed to update. Please check the logs for more information." - ) - if self.status == InferenceEndpointStatus.RUNNING and self.url is not None: - # Verify the endpoint is actually reachable - _health_url = f"{self.url.rstrip('/')}/{self.health_route.lstrip('/')}" - response = get_session().get(_health_url, headers=self._api._build_hf_headers(token=self._token)) - if response.status_code == 200: - logger.info("Inference Endpoint is ready to be used.") - return self - - if timeout is not None: - if time.time() - start > timeout: - raise InferenceEndpointTimeoutError("Timeout while waiting for Inference Endpoint to be deployed.") - logger.info(f"Inference Endpoint is not deployed yet ({self.status}). Waiting {refresh_every}s...") - time.sleep(refresh_every) - self.fetch() - - def fetch(self) -> "InferenceEndpoint": - """Fetch latest information about the Inference Endpoint. - - Returns: - [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data. - """ - obj = self._api.get_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type] - self.raw = obj.raw - self._populate_from_raw() - return self - - def update( - self, - *, - # Compute update - accelerator: Optional[str] = None, - instance_size: Optional[str] = None, - instance_type: Optional[str] = None, - min_replica: Optional[int] = None, - max_replica: Optional[int] = None, - scale_to_zero_timeout: Optional[int] = None, - # Model update - repository: Optional[str] = None, - framework: Optional[str] = None, - revision: Optional[str] = None, - task: Optional[str] = None, - custom_image: Optional[dict] = None, - secrets: Optional[dict[str, str]] = None, - ) -> "InferenceEndpoint": - """Update the Inference Endpoint. - - This method allows the update of either the compute configuration, the deployed model, or both. All arguments are - optional but at least one must be provided. - - This is an alias for [`HfApi.update_inference_endpoint`]. The current object is mutated in place with the - latest data from the server. - - Args: - accelerator (`str`, *optional*): - The hardware accelerator to be used for inference (e.g. `"cpu"`). - instance_size (`str`, *optional*): - The size or type of the instance to be used for hosting the model (e.g. `"x4"`). - instance_type (`str`, *optional*): - The cloud instance type where the Inference Endpoint will be deployed (e.g. `"intel-icl"`). - min_replica (`int`, *optional*): - The minimum number of replicas (instances) to keep running for the Inference Endpoint. - max_replica (`int`, *optional*): - The maximum number of replicas (instances) to scale to for the Inference Endpoint. - scale_to_zero_timeout (`int`, *optional*): - The duration in minutes before an inactive endpoint is scaled to zero. - - repository (`str`, *optional*): - The name of the model repository associated with the Inference Endpoint (e.g. `"gpt2"`). - framework (`str`, *optional*): - The machine learning framework used for the model (e.g. `"custom"`). - revision (`str`, *optional*): - The specific model revision to deploy on the Inference Endpoint (e.g. `"6c0e6080953db56375760c0471a8c5f2929baf11"`). - task (`str`, *optional*): - The task on which to deploy the model (e.g. `"text-classification"`). - custom_image (`dict`, *optional*): - A custom Docker image to use for the Inference Endpoint. This is useful if you want to deploy an - Inference Endpoint running on the `text-generation-inference` (TGI) framework (see examples). - secrets (`dict[str, str]`, *optional*): - Secret values to inject in the container environment. - Returns: - [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data. - """ - # Make API call - obj = self._api.update_inference_endpoint( - name=self.name, - namespace=self.namespace, - accelerator=accelerator, - instance_size=instance_size, - instance_type=instance_type, - min_replica=min_replica, - max_replica=max_replica, - scale_to_zero_timeout=scale_to_zero_timeout, - repository=repository, - framework=framework, - revision=revision, - task=task, - custom_image=custom_image, - secrets=secrets, - token=self._token, # type: ignore [arg-type] - ) - - # Mutate current object - self.raw = obj.raw - self._populate_from_raw() - return self - - def pause(self) -> "InferenceEndpoint": - """Pause the Inference Endpoint. - - A paused Inference Endpoint will not be charged. It can be resumed at any time using [`InferenceEndpoint.resume`]. - This is different from scaling the Inference Endpoint to zero with [`InferenceEndpoint.scale_to_zero`], which - would be automatically restarted when a request is made to it. - - This is an alias for [`HfApi.pause_inference_endpoint`]. The current object is mutated in place with the - latest data from the server. - - Returns: - [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data. - """ - obj = self._api.pause_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type] - self.raw = obj.raw - self._populate_from_raw() - return self - - def resume(self, running_ok: bool = True) -> "InferenceEndpoint": - """Resume the Inference Endpoint. - - This is an alias for [`HfApi.resume_inference_endpoint`]. The current object is mutated in place with the - latest data from the server. - - Args: - running_ok (`bool`, *optional*): - If `True`, the method will not raise an error if the Inference Endpoint is already running. Defaults to - `True`. - - Returns: - [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data. - """ - obj = self._api.resume_inference_endpoint( - name=self.name, namespace=self.namespace, running_ok=running_ok, token=self._token - ) # type: ignore [arg-type] - self.raw = obj.raw - self._populate_from_raw() - return self - - def scale_to_zero(self) -> "InferenceEndpoint": - """Scale Inference Endpoint to zero. - - An Inference Endpoint scaled to zero will not be charged. It will be resumed on the next request to it, with a - cold start delay. This is different from pausing the Inference Endpoint with [`InferenceEndpoint.pause`], which - would require a manual resume with [`InferenceEndpoint.resume`]. - - This is an alias for [`HfApi.scale_to_zero_inference_endpoint`]. The current object is mutated in place with the - latest data from the server. - - Returns: - [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data. - """ - obj = self._api.scale_to_zero_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type] - self.raw = obj.raw - self._populate_from_raw() - return self - - def delete(self) -> None: - """Delete the Inference Endpoint. - - This operation is not reversible. If you don't want to be charged for an Inference Endpoint, it is preferable - to pause it with [`InferenceEndpoint.pause`] or scale it to zero with [`InferenceEndpoint.scale_to_zero`]. - - This is an alias for [`HfApi.delete_inference_endpoint`]. - """ - self._api.delete_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type] - - def _populate_from_raw(self) -> None: - """Populate fields from raw dictionary. - - Called in __post_init__ + each time the Inference Endpoint is updated. - """ - # Repr fields - self.name = self.raw["name"] - self.repository = self.raw["model"]["repository"] - self.status = self.raw["status"]["state"] - self.url = self.raw["status"].get("url") - self.health_route = self.raw["healthRoute"] - - # Other fields - self.framework = self.raw["model"]["framework"] - self.revision = self.raw["model"]["revision"] - self.task = self.raw["model"]["task"] - self.created_at = parse_datetime(self.raw["status"]["createdAt"]) - self.updated_at = parse_datetime(self.raw["status"]["updatedAt"]) - self.type = self.raw["type"] diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_jobs_api.py b/venv/lib/python3.10/site-packages/huggingface_hub/_jobs_api.py deleted file mode 100644 index 914ec6d4c30c8593c0f6868389b8aa47de3ac33f..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_jobs_api.py +++ /dev/null @@ -1,399 +0,0 @@ -# coding=utf-8 -# Copyright 2025-present, the HuggingFace Inc. team. -# -# 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. -from dataclasses import dataclass -from datetime import datetime -from enum import Enum -from typing import Any, Optional, Union - -from huggingface_hub import constants -from huggingface_hub._space_api import SpaceHardware -from huggingface_hub.utils._datetime import parse_datetime - - -class JobStage(str, Enum): - """ - Enumeration of possible stage of a Job on the Hub. - - Value can be compared to a string: - ```py - assert JobStage.COMPLETED == "COMPLETED" - ``` - Possible values are: `COMPLETED`, `CANCELED`, `ERROR`, `DELETED`, `RUNNING`. - Taken from https://github.com/huggingface/moon-landing/blob/main/server/job_types/JobInfo.ts#L61 (private url). - """ - - # Copied from moon-landing > server > lib > Job.ts - COMPLETED = "COMPLETED" - CANCELED = "CANCELED" - ERROR = "ERROR" - DELETED = "DELETED" - RUNNING = "RUNNING" - - -@dataclass -class JobStatus: - stage: JobStage - message: Optional[str] - - -@dataclass -class JobOwner: - id: str - name: str - type: str - - -@dataclass -class JobInfo: - """ - Contains information about a Job. - - Args: - id (`str`): - Job ID. - created_at (`datetime` or `None`): - When the Job was created. - docker_image (`str` or `None`): - The Docker image from Docker Hub used for the Job. - Can be None if space_id is present instead. - space_id (`str` or `None`): - The Docker image from Hugging Face Spaces used for the Job. - Can be None if docker_image is present instead. - command (`list[str]` or `None`): - Command of the Job, e.g. `["python", "-c", "print('hello world')"]` - arguments (`list[str]` or `None`): - Arguments passed to the command - environment (`dict[str]` or `None`): - Environment variables of the Job as a dictionary. - secrets (`dict[str]` or `None`): - Secret environment variables of the Job (encrypted). - flavor (`str` or `None`): - Flavor for the hardware, as in Hugging Face Spaces. See [`SpaceHardware`] for possible values. - E.g. `"cpu-basic"`. - labels (`dict[str, str]` or `None`): - Labels to attach to the job (key-value pairs). - status: (`JobStatus` or `None`): - Status of the Job, e.g. `JobStatus(stage="RUNNING", message=None)` - See [`JobStage`] for possible stage values. - owner: (`JobOwner` or `None`): - Owner of the Job, e.g. `JobOwner(id="5e9ecfc04957053f60648a3e", name="lhoestq", type="user")` - - Example: - - ```python - >>> from huggingface_hub import run_job - >>> job = run_job( - ... image="python:3.12", - ... command=["python", "-c", "print('Hello from the cloud!')"] - ... ) - >>> job - JobInfo(id='687fb701029421ae5549d998', created_at=datetime.datetime(2025, 7, 22, 16, 6, 25, 79000, tzinfo=datetime.timezone.utc), docker_image='python:3.12', space_id=None, command=['python', '-c', "print('Hello from the cloud!')"], arguments=[], environment={}, secrets={}, flavor='cpu-basic', labels=None, status=JobStatus(stage='RUNNING', message=None), owner=JobOwner(id='5e9ecfc04957053f60648a3e', name='lhoestq', type='user'), endpoint='https://huggingface.co', url='https://huggingface.co/jobs/lhoestq/687fb701029421ae5549d998') - >>> job.id - '687fb701029421ae5549d998' - >>> job.url - 'https://huggingface.co/jobs/lhoestq/687fb701029421ae5549d998' - >>> job.status.stage - 'RUNNING' - ``` - """ - - id: str - created_at: Optional[datetime] - docker_image: Optional[str] - space_id: Optional[str] - command: Optional[list[str]] - arguments: Optional[list[str]] - environment: Optional[dict[str, Any]] - secrets: Optional[dict[str, Any]] - flavor: Optional[SpaceHardware] - labels: Optional[dict[str, str]] - status: JobStatus - owner: JobOwner - - # Inferred fields - endpoint: str - url: str - - def __init__(self, **kwargs) -> None: - self.id = kwargs["id"] - created_at = kwargs.get("createdAt") or kwargs.get("created_at") - self.created_at = parse_datetime(created_at) if created_at else None - self.docker_image = kwargs.get("dockerImage") or kwargs.get("docker_image") - self.space_id = kwargs.get("spaceId") or kwargs.get("space_id") - owner = kwargs.get("owner", {}) - self.owner = JobOwner(id=owner["id"], name=owner["name"], type=owner["type"]) - self.command = kwargs.get("command") - self.arguments = kwargs.get("arguments") - self.environment = kwargs.get("environment") - self.secrets = kwargs.get("secrets") - self.flavor = kwargs.get("flavor") - self.labels = kwargs.get("labels") - status = kwargs.get("status", {}) - self.status = JobStatus(stage=status["stage"], message=status.get("message")) - - # Inferred fields - self.endpoint = kwargs.get("endpoint", constants.ENDPOINT) - self.url = f"{self.endpoint}/jobs/{self.owner.name}/{self.id}" - - -@dataclass -class JobSpec: - docker_image: Optional[str] - space_id: Optional[str] - command: Optional[list[str]] - arguments: Optional[list[str]] - environment: Optional[dict[str, Any]] - secrets: Optional[dict[str, Any]] - flavor: Optional[SpaceHardware] - timeout: Optional[int] - tags: Optional[list[str]] - arch: Optional[str] - labels: Optional[dict[str, str]] - - def __init__(self, **kwargs) -> None: - self.docker_image = kwargs.get("dockerImage") or kwargs.get("docker_image") - self.space_id = kwargs.get("spaceId") or kwargs.get("space_id") - self.command = kwargs.get("command") - self.arguments = kwargs.get("arguments") - self.environment = kwargs.get("environment") - self.secrets = kwargs.get("secrets") - self.flavor = kwargs.get("flavor") - self.timeout = kwargs.get("timeout") - self.tags = kwargs.get("tags") - self.arch = kwargs.get("arch") - self.labels = kwargs.get("labels") - - -@dataclass -class LastJobInfo: - id: str - at: datetime - - def __init__(self, **kwargs) -> None: - self.id = kwargs["id"] - self.at = parse_datetime(kwargs["at"]) - - -@dataclass -class ScheduledJobStatus: - last_job: Optional[LastJobInfo] - next_job_run_at: Optional[datetime] - - def __init__(self, **kwargs) -> None: - last_job = kwargs.get("lastJob") or kwargs.get("last_job") - self.last_job = LastJobInfo(**last_job) if last_job else None - next_job_run_at = kwargs.get("nextJobRunAt") or kwargs.get("next_job_run_at") - self.next_job_run_at = parse_datetime(str(next_job_run_at)) if next_job_run_at else None - - -@dataclass -class ScheduledJobInfo: - """ - Contains information about a Job. - - Args: - id (`str`): - Scheduled Job ID. - created_at (`datetime` or `None`): - When the scheduled Job was created. - tags (`list[str]` or `None`): - The tags of the scheduled Job. - schedule (`str` or `None`): - One of "@annually", "@yearly", "@monthly", "@weekly", "@daily", "@hourly", or a - CRON schedule expression (e.g., '0 9 * * 1' for 9 AM every Monday). - suspend (`bool` or `None`): - Whether the scheduled job is suspended (paused). - concurrency (`bool` or `None`): - Whether multiple instances of this Job can run concurrently. - status (`ScheduledJobStatus` or `None`): - Status of the scheduled Job. - owner: (`JobOwner` or `None`): - Owner of the scheduled Job, e.g. `JobOwner(id="5e9ecfc04957053f60648a3e", name="lhoestq", type="user")` - job_spec: (`JobSpec` or `None`): - Specifications of the Job. - - Example: - - ```python - >>> from huggingface_hub import run_job - >>> scheduled_job = create_scheduled_job( - ... image="python:3.12", - ... command=["python", "-c", "print('Hello from the cloud!')"], - ... schedule="@hourly", - ... ) - >>> scheduled_job.id - '687fb701029421ae5549d999' - >>> scheduled_job.status.next_job_run_at - datetime.datetime(2025, 7, 22, 17, 6, 25, 79000, tzinfo=datetime.timezone.utc) - ``` - """ - - id: str - created_at: Optional[datetime] - job_spec: JobSpec - schedule: Optional[str] - suspend: Optional[bool] - concurrency: Optional[bool] - status: ScheduledJobStatus - owner: JobOwner - - def __init__(self, **kwargs) -> None: - self.id = kwargs["id"] - created_at = kwargs.get("createdAt") or kwargs.get("created_at") - self.created_at = parse_datetime(created_at) if created_at else None - self.job_spec = JobSpec(**(kwargs.get("job_spec") or kwargs.get("jobSpec", {}))) - self.schedule = kwargs.get("schedule") - self.suspend = kwargs.get("suspend") - self.concurrency = kwargs.get("concurrency") - status = kwargs.get("status", {}) - self.status = ScheduledJobStatus( - last_job=status.get("last_job") or status.get("lastJob"), - next_job_run_at=status.get("next_job_run_at") or status.get("nextJobRunAt"), - ) - owner = kwargs.get("owner", {}) - self.owner = JobOwner(id=owner["id"], name=owner["name"], type=owner["type"]) - - -@dataclass -class JobAccelerator: - """ - Contains information about a Job accelerator (GPU). - - Args: - type (`str`): - Type of accelerator, e.g. `"gpu"`. - model (`str`): - Model of accelerator, e.g. `"T4"`, `"A10G"`, `"A100"`, `"L4"`, `"L40S"`. - quantity (`str`): - Number of accelerators, e.g. `"1"`, `"2"`, `"4"`, `"8"`. - vram (`str`): - Total VRAM, e.g. `"16 GB"`, `"24 GB"`. - manufacturer (`str`): - Manufacturer of the accelerator, e.g. `"Nvidia"`. - """ - - type: str - model: str - quantity: str - vram: str - manufacturer: str - - def __init__(self, **kwargs) -> None: - self.type = kwargs["type"] - self.model = kwargs["model"] - self.quantity = kwargs["quantity"] - self.vram = kwargs["vram"] - self.manufacturer = kwargs["manufacturer"] - - -@dataclass -class JobHardware: - """ - Contains information about available Job hardware. - - Args: - name (`str`): - Machine identifier, e.g. `"cpu-basic"`, `"a10g-large"`. - pretty_name (`str`): - Human-readable name, e.g. `"CPU Basic"`, `"Nvidia A10G - large"`. - cpu (`str`): - CPU specification, e.g. `"2 vCPU"`, `"12 vCPU"`. - ram (`str`): - RAM specification, e.g. `"16 GB"`, `"46 GB"`. - accelerator (`JobAccelerator` or `None`): - GPU/accelerator details if available. - unit_cost_micro_usd (`int`): - Cost in micro-dollars per unit, e.g. `167` (= $0.000167). - unit_cost_usd (`float`): - Cost in USD per unit, e.g. `0.000167`. - unit_label (`str`): - Cost unit period, e.g. `"minute"`. - - Example: - - ```python - >>> from huggingface_hub import list_jobs_hardware - >>> hardware_list = list_jobs_hardware() - >>> hardware_list[0] - JobHardware(name='cpu-basic', pretty_name='CPU Basic', cpu='2 vCPU', ram='16 GB', accelerator=None, unit_cost_micro_usd=167, unit_cost_usd=0.000167, unit_label='minute') - >>> hardware_list[0].name - 'cpu-basic' - ``` - """ - - name: str - pretty_name: str - cpu: str - ram: str - accelerator: Optional[JobAccelerator] - unit_cost_micro_usd: int - unit_cost_usd: float - unit_label: str - - def __init__(self, **kwargs) -> None: - self.name = kwargs["name"] - self.pretty_name = kwargs["prettyName"] - self.cpu = kwargs["cpu"] - self.ram = kwargs["ram"] - accelerator = kwargs.get("accelerator") - self.accelerator = JobAccelerator(**accelerator) if accelerator else None - self.unit_cost_micro_usd = kwargs["unitCostMicroUSD"] - self.unit_cost_usd = kwargs["unitCostUSD"] - self.unit_label = kwargs["unitLabel"] - - -def _create_job_spec( - *, - image: str, - command: list[str], - env: Optional[dict[str, Any]], - secrets: Optional[dict[str, Any]], - flavor: Optional[SpaceHardware], - timeout: Optional[Union[int, float, str]], - labels: Optional[dict[str, str]] = None, -) -> dict[str, Any]: - # prepare job spec to send to HF Jobs API - job_spec: dict[str, Any] = { - "command": command, - "arguments": [], - "environment": env or {}, - "flavor": flavor or SpaceHardware.CPU_BASIC, - } - # secrets are optional - if secrets: - job_spec["secrets"] = secrets - # timeout is optional - if timeout: - time_units_factors = {"s": 1, "m": 60, "h": 3600, "d": 3600 * 24} - if isinstance(timeout, str) and timeout[-1] in time_units_factors: - job_spec["timeoutSeconds"] = int(float(timeout[:-1]) * time_units_factors[timeout[-1]]) - else: - job_spec["timeoutSeconds"] = int(timeout) - # labels are optional - if labels: - job_spec["labels"] = labels - # input is either from docker hub or from HF spaces - for prefix in ( - "https://huggingface.co/spaces/", - "https://hf.co/spaces/", - "huggingface.co/spaces/", - "hf.co/spaces/", - ): - if image.startswith(prefix): - job_spec["spaceId"] = image[len(prefix) :] - break - else: - job_spec["dockerImage"] = image - return job_spec diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_local_folder.py b/venv/lib/python3.10/site-packages/huggingface_hub/_local_folder.py deleted file mode 100644 index f213fe9e2724c0d607407397a96e59639a6f105d..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_local_folder.py +++ /dev/null @@ -1,451 +0,0 @@ -# coding=utf-8 -# Copyright 2024-present, the HuggingFace Inc. team. -# -# 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. -"""Contains utilities to handle the `../.cache/huggingface` folder in local directories. - -First discussed in https://github.com/huggingface/huggingface_hub/issues/1738 to store -download metadata when downloading files from the hub to a local directory (without -using the cache). - -./.cache/huggingface folder structure: -[4.0K] data -├── [4.0K] .cache -│ └── [4.0K] huggingface -│ └── [4.0K] download -│ ├── [ 16] file.parquet.metadata -│ ├── [ 16] file.txt.metadata -│ └── [4.0K] folder -│ └── [ 16] file.parquet.metadata -│ -├── [6.5G] file.parquet -├── [1.5K] file.txt -└── [4.0K] folder - └── [ 16] file.parquet - - -Download metadata file structure: -``` -# file.txt.metadata -11c5a3d5811f50298f278a704980280950aedb10 -a16a55fda99d2f2e7b69cce5cf93ff4ad3049930 -1712656091.123 - -# file.parquet.metadata -11c5a3d5811f50298f278a704980280950aedb10 -7c5d3f4b8b76583b422fcb9189ad6c89d5d97a094541ce8932dce3ecabde1421 -1712656091.123 -} -``` -""" - -import base64 -import hashlib -import logging -import os -import time -from dataclasses import dataclass -from pathlib import Path -from typing import Optional - -from .utils import WeakFileLock - - -logger = logging.getLogger(__name__) - - -@dataclass -class LocalDownloadFilePaths: - """ - Paths to the files related to a download process in a local dir. - - Returned by [`get_local_download_paths`]. - - Attributes: - file_path (`Path`): - Path where the file will be saved. - lock_path (`Path`): - Path to the lock file used to ensure atomicity when reading/writing metadata. - metadata_path (`Path`): - Path to the metadata file. - """ - - file_path: Path - lock_path: Path - metadata_path: Path - - def incomplete_path(self, etag: str) -> Path: - """Return the path where a file will be temporarily downloaded before being moved to `file_path`.""" - path = self.metadata_path.parent / f"{_short_hash(self.metadata_path.name)}.{etag}.incomplete" - resolved_path = str(path.resolve()) - # Some Windows versions do not allow for paths longer than 255 characters. - # In this case, we must specify it as an extended path by using the "\\?\" prefix. - if os.name == "nt" and len(resolved_path) > 255 and not resolved_path.startswith("\\\\?\\"): - path = Path("\\\\?\\" + resolved_path) - return path - - -@dataclass(frozen=True) -class LocalUploadFilePaths: - """ - Paths to the files related to an upload process in a local dir. - - Returned by [`get_local_upload_paths`]. - - Attributes: - path_in_repo (`str`): - Path of the file in the repo. - file_path (`Path`): - Path where the file will be saved. - lock_path (`Path`): - Path to the lock file used to ensure atomicity when reading/writing metadata. - metadata_path (`Path`): - Path to the metadata file. - """ - - path_in_repo: str - file_path: Path - lock_path: Path - metadata_path: Path - - -@dataclass -class LocalDownloadFileMetadata: - """ - Metadata about a file in the local directory related to a download process. - - Attributes: - filename (`str`): - Path of the file in the repo. - commit_hash (`str`): - Commit hash of the file in the repo. - etag (`str`): - ETag of the file in the repo. Used to check if the file has changed. - For LFS files, this is the sha256 of the file. For regular files, it corresponds to the git hash. - timestamp (`int`): - Unix timestamp of when the metadata was saved i.e. when the metadata was accurate. - """ - - filename: str - commit_hash: str - etag: str - timestamp: float - - -@dataclass -class LocalUploadFileMetadata: - """ - Metadata about a file in the local directory related to an upload process. - """ - - size: int - - # Default values correspond to "we don't know yet" - timestamp: Optional[float] = None - should_ignore: Optional[bool] = None - sha256: Optional[str] = None - upload_mode: Optional[str] = None - remote_oid: Optional[str] = None - is_uploaded: bool = False - is_committed: bool = False - - def save(self, paths: LocalUploadFilePaths) -> None: - """Save the metadata to disk.""" - with WeakFileLock(paths.lock_path): - with paths.metadata_path.open("w") as f: - new_timestamp = time.time() - f.write(str(new_timestamp) + "\n") - - f.write(str(self.size)) # never None - f.write("\n") - - if self.should_ignore is not None: - f.write(str(int(self.should_ignore))) - f.write("\n") - - if self.sha256 is not None: - f.write(self.sha256) - f.write("\n") - - if self.upload_mode is not None: - f.write(self.upload_mode) - f.write("\n") - - if self.remote_oid is not None: - f.write(self.remote_oid) - f.write("\n") - - f.write(str(int(self.is_uploaded)) + "\n") - f.write(str(int(self.is_committed)) + "\n") - - self.timestamp = new_timestamp - - -def get_local_download_paths(local_dir: Path, filename: str) -> LocalDownloadFilePaths: - """Compute paths to the files related to a download process. - - Folders containing the paths are all guaranteed to exist. - - Args: - local_dir (`Path`): - Path to the local directory in which files are downloaded. - filename (`str`): - Path of the file in the repo. - - Return: - [`LocalDownloadFilePaths`]: the paths to the files (file_path, lock_path, metadata_path, incomplete_path). - """ - # filename is the path in the Hub repository (separated by '/') - # make sure to have a cross-platform transcription - sanitized_filename = os.path.join(*filename.split("/")) - if os.name == "nt": - if sanitized_filename.startswith("..\\") or "\\..\\" in sanitized_filename: - raise ValueError( - f"Invalid filename: cannot handle filename '{sanitized_filename}' on Windows. Please ask the repository" - " owner to rename this file." - ) - file_path = local_dir / sanitized_filename - metadata_path = _huggingface_dir(local_dir) / "download" / f"{sanitized_filename}.metadata" - lock_path = metadata_path.with_suffix(".lock") - - # Some Windows versions do not allow for paths longer than 255 characters. - # In this case, we must specify it as an extended path by using the "\\?\" prefix - if os.name == "nt": - if not str(local_dir).startswith("\\\\?\\") and len(os.path.abspath(lock_path)) > 255: - file_path = Path("\\\\?\\" + os.path.abspath(file_path)) - lock_path = Path("\\\\?\\" + os.path.abspath(lock_path)) - metadata_path = Path("\\\\?\\" + os.path.abspath(metadata_path)) - - file_path.parent.mkdir(parents=True, exist_ok=True) - metadata_path.parent.mkdir(parents=True, exist_ok=True) - return LocalDownloadFilePaths(file_path=file_path, lock_path=lock_path, metadata_path=metadata_path) - - -def get_local_upload_paths(local_dir: Path, filename: str) -> LocalUploadFilePaths: - """Compute paths to the files related to an upload process. - - Folders containing the paths are all guaranteed to exist. - - Args: - local_dir (`Path`): - Path to the local directory that is uploaded. - filename (`str`): - Path of the file in the repo. - - Return: - [`LocalUploadFilePaths`]: the paths to the files (file_path, lock_path, metadata_path). - """ - # filename is the path in the Hub repository (separated by '/') - # make sure to have a cross-platform transcription - sanitized_filename = os.path.join(*filename.split("/")) - if os.name == "nt": - if sanitized_filename.startswith("..\\") or "\\..\\" in sanitized_filename: - raise ValueError( - f"Invalid filename: cannot handle filename '{sanitized_filename}' on Windows. Please ask the repository" - " owner to rename this file." - ) - file_path = local_dir / sanitized_filename - metadata_path = _huggingface_dir(local_dir) / "upload" / f"{sanitized_filename}.metadata" - lock_path = metadata_path.with_suffix(".lock") - - # Some Windows versions do not allow for paths longer than 255 characters. - # In this case, we must specify it as an extended path by using the "\\?\" prefix - if os.name == "nt": - if not str(local_dir).startswith("\\\\?\\") and len(os.path.abspath(lock_path)) > 255: - file_path = Path("\\\\?\\" + os.path.abspath(file_path)) - lock_path = Path("\\\\?\\" + os.path.abspath(lock_path)) - metadata_path = Path("\\\\?\\" + os.path.abspath(metadata_path)) - - file_path.parent.mkdir(parents=True, exist_ok=True) - metadata_path.parent.mkdir(parents=True, exist_ok=True) - return LocalUploadFilePaths( - path_in_repo=filename, file_path=file_path, lock_path=lock_path, metadata_path=metadata_path - ) - - -def read_download_metadata(local_dir: Path, filename: str) -> Optional[LocalDownloadFileMetadata]: - """Read metadata about a file in the local directory related to a download process. - - Args: - local_dir (`Path`): - Path to the local directory in which files are downloaded. - filename (`str`): - Path of the file in the repo. - - Return: - `[LocalDownloadFileMetadata]` or `None`: the metadata if it exists, `None` otherwise. - """ - paths = get_local_download_paths(local_dir, filename) - with WeakFileLock(paths.lock_path): - if paths.metadata_path.exists(): - try: - with paths.metadata_path.open() as f: - commit_hash = f.readline().strip() - etag = f.readline().strip() - timestamp = float(f.readline().strip()) - metadata = LocalDownloadFileMetadata( - filename=filename, - commit_hash=commit_hash, - etag=etag, - timestamp=timestamp, - ) - except Exception as e: - # remove the metadata file if it is corrupted / not the right format - logger.warning( - f"Invalid metadata file {paths.metadata_path}: {e}. Removing it from disk and continue." - ) - try: - paths.metadata_path.unlink() - except Exception as e: - logger.warning(f"Could not remove corrupted metadata file {paths.metadata_path}: {e}") - return None - - try: - # check if the file exists and hasn't been modified since the metadata was saved - stat = paths.file_path.stat() - if ( - stat.st_mtime - 1 <= metadata.timestamp - ): # allow 1s difference as stat.st_mtime might not be precise - return metadata - logger.info(f"Ignored metadata for '{filename}' (outdated). Will re-compute hash.") - except FileNotFoundError: - # file does not exist => metadata is outdated - return None - return None - - -def read_upload_metadata(local_dir: Path, filename: str) -> LocalUploadFileMetadata: - """Read metadata about a file in the local directory related to an upload process. - - TODO: factorize logic with `read_download_metadata`. - - Args: - local_dir (`Path`): - Path to the local directory in which files are downloaded. - filename (`str`): - Path of the file in the repo. - - Return: - `[LocalUploadFileMetadata]` or `None`: the metadata if it exists, `None` otherwise. - """ - paths = get_local_upload_paths(local_dir, filename) - with WeakFileLock(paths.lock_path): - if paths.metadata_path.exists(): - try: - with paths.metadata_path.open() as f: - timestamp = float(f.readline().strip()) - - size = int(f.readline().strip()) # never None - - _should_ignore = f.readline().strip() - should_ignore = None if _should_ignore == "" else bool(int(_should_ignore)) - - _sha256 = f.readline().strip() - sha256 = None if _sha256 == "" else _sha256 - - _upload_mode = f.readline().strip() - upload_mode = None if _upload_mode == "" else _upload_mode - if upload_mode not in (None, "regular", "lfs"): - raise ValueError(f"Invalid upload mode in metadata {paths.path_in_repo}: {upload_mode}") - - _remote_oid = f.readline().strip() - remote_oid = None if _remote_oid == "" else _remote_oid - - is_uploaded = bool(int(f.readline().strip())) - is_committed = bool(int(f.readline().strip())) - - metadata = LocalUploadFileMetadata( - timestamp=timestamp, - size=size, - should_ignore=should_ignore, - sha256=sha256, - upload_mode=upload_mode, - remote_oid=remote_oid, - is_uploaded=is_uploaded, - is_committed=is_committed, - ) - except Exception as e: - # remove the metadata file if it is corrupted / not the right format - logger.warning( - f"Invalid metadata file {paths.metadata_path}: {e}. Removing it from disk and continue." - ) - try: - paths.metadata_path.unlink() - except Exception as e: - logger.warning(f"Could not remove corrupted metadata file {paths.metadata_path}: {e}") - - # corrupted metadata => we don't know anything expect its size - return LocalUploadFileMetadata(size=paths.file_path.stat().st_size) - - # TODO: can we do better? - if ( - metadata.timestamp is not None - and metadata.is_uploaded # file was uploaded - and not metadata.is_committed # but not committed - and time.time() - metadata.timestamp > 20 * 3600 # and it's been more than 20 hours - ): # => we consider it as garbage-collected by S3 - metadata.is_uploaded = False - - # check if the file exists and hasn't been modified since the metadata was saved - try: - if metadata.timestamp is not None and paths.file_path.stat().st_mtime <= metadata.timestamp: - return metadata - logger.info(f"Ignored metadata for '{filename}' (outdated). Will re-compute hash.") - except FileNotFoundError: - # file does not exist => metadata is outdated - pass - - # empty metadata => we don't know anything expect its size - return LocalUploadFileMetadata(size=paths.file_path.stat().st_size) - - -def write_download_metadata(local_dir: Path, filename: str, commit_hash: str, etag: str) -> None: - """Write metadata about a file in the local directory related to a download process. - - Args: - local_dir (`Path`): - Path to the local directory in which files are downloaded. - """ - paths = get_local_download_paths(local_dir, filename) - with WeakFileLock(paths.lock_path): - with paths.metadata_path.open("w") as f: - f.write(f"{commit_hash}\n{etag}\n{time.time()}\n") - - -def _huggingface_dir(local_dir: Path) -> Path: - """Return the path to the `.cache/huggingface` directory in a local directory.""" - # Wrap in lru_cache to avoid overwriting the .gitignore file if called multiple times - path = local_dir / ".cache" / "huggingface" - path.mkdir(exist_ok=True, parents=True) - - # Create a .gitignore file in the .cache/huggingface directory if it doesn't exist - # Should be thread-safe enough like this. - gitignore = path / ".gitignore" - gitignore_lock = path / ".gitignore.lock" - if not gitignore.exists(): - try: - with WeakFileLock(gitignore_lock, timeout=0.1): - gitignore.write_text("*") - except IndexError: - pass - except OSError: # TimeoutError, FileNotFoundError, PermissionError, etc. - pass - try: - gitignore_lock.unlink() - except OSError: - pass - return path - - -def _short_hash(filename: str) -> str: - return base64.urlsafe_b64encode(hashlib.sha1(filename.encode()).digest()).decode() diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_login.py b/venv/lib/python3.10/site-packages/huggingface_hub/_login.py deleted file mode 100644 index fe266d2deac58d94109aaedb4e9a6ee162d8f0a5..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_login.py +++ /dev/null @@ -1,492 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# 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. -"""Contains methods to log in to the Hub.""" - -import os -import subprocess -from getpass import getpass -from pathlib import Path -from typing import Optional - -import typer - -from . import constants -from .utils import ( - ANSI, - capture_output, - get_token, - is_google_colab, - is_notebook, - list_credential_helpers, - logging, - run_subprocess, - set_git_credential, - unset_git_credential, -) -from .utils._auth import ( - _get_token_by_name, - _get_token_from_environment, - _get_token_from_file, - _get_token_from_google_colab, - _save_stored_tokens, - _save_token, - get_stored_tokens, -) - - -logger = logging.get_logger(__name__) - -_HF_LOGO_ASCII = """ - _| _| _| _| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _|_|_|_| _|_| _|_|_| _|_|_|_| - _| _| _| _| _| _| _| _|_| _| _| _| _| _| _| _| - _|_|_|_| _| _| _| _|_| _| _|_| _| _| _| _| _| _|_| _|_|_| _|_|_|_| _| _|_|_| - _| _| _| _| _| _| _| _| _| _| _|_| _| _| _| _| _| _| _| - _| _| _|_| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _| _| _| _|_|_| _|_|_|_| -""" - - -def login( - token: Optional[str] = None, - *, - add_to_git_credential: bool = False, - skip_if_logged_in: bool = False, -) -> None: - """Login the machine to access the Hub. - - The `token` is persisted in cache and set as a git credential. Once done, the machine - is logged in and the access token will be available across all `huggingface_hub` - components. If `token` is not provided, it will be prompted to the user either with - a widget (in a notebook) or via the terminal. - - To log in from outside of a script, one can also use `hf auth login` which is - a cli command that wraps [`login`]. - - > [!TIP] - > [`login`] is a drop-in replacement method for [`notebook_login`] as it wraps and - > extends its capabilities. - - > [!TIP] - > When the token is not passed, [`login`] will automatically detect if the script runs - > in a notebook or not. However, this detection might not be accurate due to the - > variety of notebooks that exists nowadays. If that is the case, you can always force - > the UI by using [`notebook_login`] or [`interpreter_login`]. - - Args: - token (`str`, *optional*): - User access token to generate from https://huggingface.co/settings/token. - add_to_git_credential (`bool`, defaults to `False`): - If `True`, token will be set as git credential. If no git credential helper - is configured, a warning will be displayed to the user. If `token` is `None`, - the value of `add_to_git_credential` is ignored and will be prompted again - to the end user. - skip_if_logged_in (`bool`, defaults to `False`): - If `True`, do not prompt for token if user is already logged in. - Raises: - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If an organization token is passed. Only personal account tokens are valid - to log in. - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - If token is invalid. - [`ImportError`](https://docs.python.org/3/library/exceptions.html#ImportError) - If running in a notebook but `ipywidgets` is not installed. - """ - if token is not None: - if not add_to_git_credential: - logger.info( - "The token has not been saved to the git credentials helper. Pass " - "`add_to_git_credential=True` in this function directly or " - "`--add-to-git-credential` if using via `hf`CLI if " - "you want to set the git credential as well." - ) - _login(token, add_to_git_credential=add_to_git_credential) - elif is_notebook(): - notebook_login(skip_if_logged_in=skip_if_logged_in) - else: - interpreter_login(skip_if_logged_in=skip_if_logged_in) - - -def logout(token_name: Optional[str] = None) -> None: - """Logout the machine from the Hub. - - Token is deleted from the machine and removed from git credential. - - Args: - token_name (`str`, *optional*): - Name of the access token to logout from. If `None`, will log out from all saved access tokens. - Raises: - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError): - If the access token name is not found. - """ - if get_token() is None and not get_stored_tokens(): # No active token and no saved access tokens - logger.warning("Not logged in!") - return - if not token_name: - # Delete all saved access tokens and token - for file_path in (constants.HF_TOKEN_PATH, constants.HF_STORED_TOKENS_PATH): - try: - Path(file_path).unlink() - except FileNotFoundError: - pass - logger.info("Successfully logged out from all access tokens.") - else: - _logout_from_token(token_name) - logger.info(f"Successfully logged out from access token: {token_name}.") - - unset_git_credential() - - # Check if still logged in - if _get_token_from_google_colab() is not None: - raise EnvironmentError( - "You are automatically logged in using a Google Colab secret.\n" - "To log out, you must unset the `HF_TOKEN` secret in your Colab settings." - ) - if _get_token_from_environment() is not None: - raise EnvironmentError( - "Token has been deleted from your machine but you are still logged in.\n" - "To log out, you must clear out both `HF_TOKEN` and `HUGGING_FACE_HUB_TOKEN` environment variables." - ) - - -def auth_switch(token_name: str, add_to_git_credential: bool = False) -> None: - """Switch to a different access token. - - Args: - token_name (`str`): - Name of the access token to switch to. - add_to_git_credential (`bool`, defaults to `False`): - If `True`, token will be set as git credential. If no git credential helper - is configured, a warning will be displayed to the user. If `token` is `None`, - the value of `add_to_git_credential` is ignored and will be prompted again - to the end user. - - Raises: - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError): - If the access token name is not found. - """ - token = _get_token_by_name(token_name) - if not token: - raise ValueError(f"Access token {token_name} not found in {constants.HF_STORED_TOKENS_PATH}") - # Write token to HF_TOKEN_PATH - _set_active_token(token_name, add_to_git_credential) - logger.info(f"The current active token is: {token_name}") - token_from_environment = _get_token_from_environment() - if token_from_environment is not None and token_from_environment != token: - logger.warning( - "The environment variable `HF_TOKEN` is set and will override the access token you've just switched to." - ) - - -def auth_list() -> None: - """List all stored access tokens.""" - tokens = get_stored_tokens() - - if not tokens: - if _get_token_from_environment(): - logger.info("No stored access tokens found.") - logger.warning("Note: Environment variable `HF_TOKEN` is set and is the current active token.") - else: - logger.info("No access tokens found.") - return - # Find current token - current_token = get_token() - current_token_name = None - for token_name in tokens: - if tokens.get(token_name) == current_token: - current_token_name = token_name - # Print header - max_offset = max(len("token"), max(len(token) for token in tokens)) + 2 - print(f" {{:<{max_offset}}}| {{:<15}}".format("name", "token")) - print("-" * (max_offset + 2) + "|" + "-" * 15) - - # Print saved access tokens - for token_name in tokens: - token = tokens.get(token_name, "") - masked_token = f"{token[:3]}****{token[-4:]}" if token != "" else token - is_current = "*" if token == current_token else " " - - print(f"{is_current} {{:<{max_offset}}}| {{:<15}}".format(token_name, masked_token)) - - if _get_token_from_environment(): - logger.warning( - "\nNote: Environment variable `HF_TOKEN` is set and is the current active token independently from the stored tokens listed above." - ) - elif current_token_name is None: - logger.warning( - "\nNote: No active token is set and no environment variable `HF_TOKEN` is found. Use `hf auth login` to log in." - ) - - -### -# Interpreter-based login (text) -### - - -def interpreter_login(*, skip_if_logged_in: bool = False) -> None: - """ - Displays a prompt to log in to the HF website and store the token. - - This is equivalent to [`login`] without passing a token when not run in a notebook. - [`interpreter_login`] is useful if you want to force the use of the terminal prompt - instead of a notebook widget. - - For more details, see [`login`]. - - Args: - skip_if_logged_in (`bool`, defaults to `False`): - If `True`, do not prompt for token if user is already logged in. - """ - if not skip_if_logged_in and get_token() is not None: - logger.info("User is already logged in.") - return - - print(_HF_LOGO_ASCII) - if get_token() is not None: - logger.info( - " A token is already saved on your machine. Run `hf auth whoami`" - " to get more information or `hf auth logout` if you want" - " to log out." - ) - logger.info(" Setting a new token will erase the existing one.") - - logger.info( - " To log in, `huggingface_hub` requires a token generated from https://huggingface.co/settings/tokens ." - ) - if os.name == "nt": - logger.info("Token can be pasted using 'Right-Click'.") - token = getpass("Enter your token (input will not be visible): ") - add_to_git_credential = typer.confirm("Add token as git credential?") - - _login(token=token, add_to_git_credential=add_to_git_credential) - - -### -# Notebook-based login (widget) -### - -NOTEBOOK_LOGIN_PASSWORD_HTML = """

Immediately click login after typing your password or -it might be stored in plain text in this notebook file.
""" - - -NOTEBOOK_LOGIN_TOKEN_HTML_START = """

Copy a token from your Hugging Face -tokens page and paste it below.
Immediately click login after copying -your token or it might be stored in plain text in this notebook file.
""" - - -NOTEBOOK_LOGIN_TOKEN_HTML_END = """ -Pro Tip: If you don't already have one, you can create a dedicated -'notebooks' token with 'write' access, that you can then easily reuse for all -notebooks. """ - - -def notebook_login(*, skip_if_logged_in: bool = False) -> None: - """ - Displays a widget to log in to the HF website and store the token. - - This is equivalent to [`login`] without passing a token when run in a notebook. - [`notebook_login`] is useful if you want to force the use of the notebook widget - instead of a prompt in the terminal. - - For more details, see [`login`]. - - Args: - skip_if_logged_in (`bool`, defaults to `False`): - If `True`, do not prompt for token if user is already logged in. - """ - try: - import ipywidgets.widgets as widgets # type: ignore - from IPython.display import display # type: ignore - except ImportError: - raise ImportError( - "The `notebook_login` function can only be used in a notebook (Jupyter or" - " Colab) and you need the `ipywidgets` module: `pip install ipywidgets`." - ) - if not skip_if_logged_in and get_token() is not None: - logger.info("User is already logged in.") - return - - box_layout = widgets.Layout(display="flex", flex_flow="column", align_items="center", width="50%") - - token_widget = widgets.Password(description="Token:") - git_checkbox_widget = widgets.Checkbox(value=True, description="Add token as git credential?") - token_finish_button = widgets.Button(description="Login") - - login_token_widget = widgets.VBox( - [ - widgets.HTML(NOTEBOOK_LOGIN_TOKEN_HTML_START), - token_widget, - git_checkbox_widget, - token_finish_button, - widgets.HTML(NOTEBOOK_LOGIN_TOKEN_HTML_END), - ], - layout=box_layout, - ) - display(login_token_widget) - - # On click events - def login_token_event(t): - """Event handler for the login button.""" - token = token_widget.value - add_to_git_credential = git_checkbox_widget.value - # Erase token and clear value to make sure it's not saved in the notebook. - token_widget.value = "" - # Hide inputs - login_token_widget.children = [widgets.Label("Connecting...")] - try: - with capture_output() as captured: - _login(token, add_to_git_credential=add_to_git_credential) - message = captured.getvalue() - except Exception as error: - message = str(error) - # Print result (success message or error) - login_token_widget.children = [widgets.Label(line) for line in message.split("\n") if line.strip()] - - token_finish_button.on_click(login_token_event) - - -### -# Login private helpers -### - - -def _login( - token: str, - add_to_git_credential: bool, -) -> None: - from .hf_api import whoami # avoid circular import - - if token.startswith("api_org"): - raise ValueError("You must use your personal account token, not an organization token.") - - token_info = whoami(token) - permission = token_info["auth"]["accessToken"]["role"] - logger.info(f"Token is valid (permission: {permission}).") - - token_name = token_info["auth"]["accessToken"]["displayName"] - # Store token locally - _save_token(token=token, token_name=token_name) - # Set active token - _set_active_token(token_name=token_name, add_to_git_credential=add_to_git_credential) - logger.info("Login successful.") - if _get_token_from_environment(): - logger.warning( - "Note: Environment variable`HF_TOKEN` is set and is the current active token independently from the token you've just configured." - ) - else: - logger.info(f"The current active token is: `{token_name}`") - - -def _logout_from_token(token_name: str) -> None: - """Logout from a specific access token. - - Args: - token_name (`str`): - The name of the access token to logout from. - Raises: - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError): - If the access token name is not found. - """ - stored_tokens = get_stored_tokens() - # If there is no access tokens saved or the access token name is not found, do nothing - if not stored_tokens or token_name not in stored_tokens: - return - - token = stored_tokens.pop(token_name) - _save_stored_tokens(stored_tokens) - - if token == _get_token_from_file(): - logger.warning(f"Active token '{token_name}' has been deleted.") - Path(constants.HF_TOKEN_PATH).unlink(missing_ok=True) - - -def _set_active_token( - token_name: str, - add_to_git_credential: bool, -) -> None: - """Set the active access token. - - Args: - token_name (`str`): - The name of the token to set as active. - """ - token = _get_token_by_name(token_name) - if not token: - raise ValueError(f"Token {token_name} not found in {constants.HF_STORED_TOKENS_PATH}") - if add_to_git_credential: - if _is_git_credential_helper_configured(): - set_git_credential(token) - logger.info( - "Your token has been saved in your configured git credential helpers" - + f" ({','.join(list_credential_helpers())})." - ) - else: - logger.warning("Token has not been saved to git credential helper.") - # Write token to HF_TOKEN_PATH - path = Path(constants.HF_TOKEN_PATH) - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(token) - logger.info(f"Your token has been saved to {constants.HF_TOKEN_PATH}") - - -def _is_git_credential_helper_configured() -> bool: - """Check if a git credential helper is configured. - - Warns user if not the case (except for Google Colab where "store" is set by default - by `huggingface_hub`). - """ - helpers = list_credential_helpers() - if len(helpers) > 0: - return True # Do not warn: at least 1 helper is set - - # Only in Google Colab to avoid the warning message - # See https://github.com/huggingface/huggingface_hub/issues/1043#issuecomment-1247010710 - if is_google_colab(): - _set_store_as_git_credential_helper_globally() - return True # Do not warn: "store" is used by default in Google Colab - - # Otherwise, warn user - print( - ANSI.red( - "Cannot authenticate through git-credential as no helper is defined on your" - " machine.\nYou might have to re-authenticate when pushing to the Hugging" - " Face Hub.\nRun the following command in your terminal in case you want to" - " set the 'store' credential helper as default.\n\ngit config --global" - " credential.helper store\n\nRead" - " https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage for more" - " details." - ) - ) - return False - - -def _set_store_as_git_credential_helper_globally() -> None: - """Set globally the credential.helper to `store`. - - To be used only in Google Colab as we assume the user doesn't care about the git - credential config. It is the only particular case where we don't want to display the - warning message in [`notebook_login()`]. - - Related: - - https://github.com/huggingface/huggingface_hub/issues/1043 - - https://github.com/huggingface/huggingface_hub/issues/1051 - - https://git-scm.com/docs/git-credential-store - """ - try: - run_subprocess("git config --global credential.helper store") - except subprocess.CalledProcessError as exc: - raise EnvironmentError(exc.stderr) diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_oauth.py b/venv/lib/python3.10/site-packages/huggingface_hub/_oauth.py deleted file mode 100644 index 0594c7b56b808d12a37bbf419c59d335a31c03ff..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_oauth.py +++ /dev/null @@ -1,460 +0,0 @@ -import datetime -import hashlib -import logging -import os -import time -import urllib.parse -import warnings -from dataclasses import dataclass -from typing import TYPE_CHECKING, Literal, Optional, Union - -from . import constants -from .hf_api import whoami -from .utils import experimental, get_token - - -logger = logging.getLogger(__name__) - -if TYPE_CHECKING: - import fastapi - - -@dataclass -class OAuthOrgInfo: - """ - Information about an organization linked to a user logged in with OAuth. - - Attributes: - sub (`str`): - Unique identifier for the org. OpenID Connect field. - name (`str`): - The org's full name. OpenID Connect field. - preferred_username (`str`): - The org's username. OpenID Connect field. - picture (`str`): - The org's profile picture URL. OpenID Connect field. - plan (`str`, *optional*): - The org's plan (e.g., "enterprise", "team"). Hugging Face field. - can_pay (`Optional[bool]`, *optional*): - Whether the org has a payment method set up. Hugging Face field. - role_in_org (`Optional[str]`, *optional*): - The user's role in the org. Hugging Face field. - security_restrictions (`Optional[list[Literal["ip", "token-policy", "mfa", "sso"]]]`, *optional*): - Array of security restrictions that the user hasn't completed for this org. Possible values: "ip", "token-policy", "mfa", "sso". Hugging Face field. - """ - - sub: str - name: str - preferred_username: str - picture: str - plan: Optional[str] = None - can_pay: Optional[bool] = None - role_in_org: Optional[str] = None - security_restrictions: Optional[list[Literal["ip", "token-policy", "mfa", "sso"]]] = None - - -@dataclass -class OAuthUserInfo: - """ - Information about a user logged in with OAuth. - - Attributes: - sub (`str`): - Unique identifier for the user, even in case of rename. OpenID Connect field. - name (`str`): - The user's full name. OpenID Connect field. - preferred_username (`str`): - The user's username. OpenID Connect field. - email_verified (`Optional[bool]`, *optional*): - Indicates if the user's email is verified. OpenID Connect field. - email (`Optional[str]`, *optional*): - The user's email address. OpenID Connect field. - picture (`str`): - The user's profile picture URL. OpenID Connect field. - profile (`str`): - The user's profile URL. OpenID Connect field. - website (`Optional[str]`, *optional*): - The user's website URL. OpenID Connect field. - is_pro (`bool`): - Whether the user is a pro user. Hugging Face field. - can_pay (`Optional[bool]`, *optional*): - Whether the user has a payment method set up. Hugging Face field. - orgs (`Optional[list[OrgInfo]]`, *optional*): - List of organizations the user is part of. Hugging Face field. - """ - - sub: str - name: str - preferred_username: str - email_verified: Optional[bool] - email: Optional[str] - picture: str - profile: str - website: Optional[str] - is_pro: bool - can_pay: Optional[bool] - orgs: Optional[list[OAuthOrgInfo]] - - -@dataclass -class OAuthInfo: - """ - Information about the OAuth login. - - Attributes: - access_token (`str`): - The access token. - access_token_expires_at (`datetime.datetime`): - The expiration date of the access token. - user_info ([`OAuthUserInfo`]): - The user information. - state (`str`, *optional*): - State passed to the OAuth provider in the original request to the OAuth provider. - scope (`str`): - Granted scope. - """ - - access_token: str - access_token_expires_at: datetime.datetime - user_info: OAuthUserInfo - state: Optional[str] - scope: str - - -@experimental -def attach_huggingface_oauth(app: "fastapi.FastAPI", route_prefix: str = "/"): - """ - Add OAuth endpoints to a FastAPI app to enable OAuth login with Hugging Face. - - How to use: - - Call this method on your FastAPI app to add the OAuth endpoints. - - Inside your route handlers, call `parse_huggingface_oauth(request)` to retrieve the OAuth info. - - If user is logged in, an [`OAuthInfo`] object is returned with the user's info. If not, `None` is returned. - - In your app, make sure to add links to `/oauth/huggingface/login` and `/oauth/huggingface/logout` for the user to log in and out. - - Example: - ```py - from huggingface_hub import attach_huggingface_oauth, parse_huggingface_oauth - - # Create a FastAPI app - app = FastAPI() - - # Add OAuth endpoints to the FastAPI app - attach_huggingface_oauth(app) - - # Add a route that greets the user if they are logged in - @app.get("/") - def greet_json(request: Request): - # Retrieve the OAuth info from the request - oauth_info = parse_huggingface_oauth(request) # e.g. OAuthInfo dataclass - if oauth_info is None: - return {"msg": "Not logged in!"} - return {"msg": f"Hello, {oauth_info.user_info.preferred_username}!"} - ``` - """ - # TODO: handle generic case (handling OAuth in a non-Space environment with custom dev values) (low priority) - - # Add SessionMiddleware to the FastAPI app to store the OAuth info in the session. - # Session Middleware requires a secret key to sign the cookies. Let's use a hash - # of the OAuth secret key to make it unique to the Space + updated in case OAuth - # config gets updated. When ran locally, we use an empty string as a secret key. - try: - from starlette.middleware.sessions import SessionMiddleware - except ImportError as e: - raise ImportError( - "Cannot initialize OAuth to due a missing library. Please run `pip install huggingface_hub[oauth]` or add " - "`huggingface_hub[oauth]` to your requirements.txt file in order to install the required dependencies." - ) from e - session_secret = (constants.OAUTH_CLIENT_SECRET or "") + "-v1" - app.add_middleware( - SessionMiddleware, # type: ignore[arg-type] - secret_key=hashlib.sha256(session_secret.encode()).hexdigest(), - same_site="none", - https_only=True, - ) # type: ignore - - # Add OAuth endpoints to the FastAPI app: - # - {route_prefix}/oauth/huggingface/login - # - {route_prefix}/oauth/huggingface/callback - # - {route_prefix}/oauth/huggingface/logout - # If the app is running in a Space, OAuth is enabled normally. - # Otherwise, we mock the endpoints to make the user log in with a fake user profile - without any calls to hf.co. - route_prefix = route_prefix.strip("/") - if os.getenv("SPACE_ID") is not None: - logger.info("OAuth is enabled in the Space. Adding OAuth routes.") - _add_oauth_routes(app, route_prefix=route_prefix) - else: - logger.info("App is not running in a Space. Adding mocked OAuth routes.") - _add_mocked_oauth_routes(app, route_prefix=route_prefix) - - -def parse_huggingface_oauth(request: "fastapi.Request") -> Optional[OAuthInfo]: - """ - Returns the information from a logged-in user as a [`OAuthInfo`] object. - - For flexibility and future-proofing, this method is very lax in its parsing and does not raise errors. - Missing fields are set to `None` without a warning. - - Return `None`, if the user is not logged in (no info in session cookie). - - See [`attach_huggingface_oauth`] for an example on how to use this method. - """ - if "oauth_info" not in request.session: - logger.debug("No OAuth info in session.") - return None - - logger.debug("Parsing OAuth info from session.") - oauth_data = request.session["oauth_info"] - user_data = oauth_data.get("userinfo", {}) - orgs_data = user_data.get("orgs", []) - - orgs = ( - [ - OAuthOrgInfo( - sub=org.get("sub"), - name=org.get("name"), - preferred_username=org.get("preferred_username"), - picture=org.get("picture"), - plan=org.get("plan"), - can_pay=org.get("canPay"), - role_in_org=org.get("roleInOrg"), - security_restrictions=org.get("securityRestrictions"), - ) - for org in orgs_data - ] - if orgs_data - else None - ) - - user_info = OAuthUserInfo( - sub=user_data.get("sub"), - name=user_data.get("name"), - preferred_username=user_data.get("preferred_username"), - email_verified=user_data.get("email_verified"), - email=user_data.get("email"), - picture=user_data.get("picture"), - profile=user_data.get("profile"), - website=user_data.get("website"), - is_pro=user_data.get("isPro"), - can_pay=user_data.get("canPay"), - orgs=orgs, - ) - - return OAuthInfo( - access_token=oauth_data.get("access_token"), - access_token_expires_at=datetime.datetime.fromtimestamp(oauth_data.get("expires_at")), - user_info=user_info, - state=oauth_data.get("state"), - scope=oauth_data.get("scope"), - ) - - -def _add_oauth_routes(app: "fastapi.FastAPI", route_prefix: str) -> None: - """Add OAuth routes to the FastAPI app (login, callback handler and logout).""" - try: - import fastapi - from authlib.integrations.base_client.errors import MismatchingStateError - from authlib.integrations.starlette_client import OAuth - from fastapi.responses import RedirectResponse - except ImportError as e: - raise ImportError( - "Cannot initialize OAuth to due a missing library. Please run `pip install huggingface_hub[oauth]` or add " - "`huggingface_hub[oauth]` to your requirements.txt file." - ) from e - - # Check environment variables - msg = ( - "OAuth is required but '{}' environment variable is not set. Make sure you've enabled OAuth in your Space by" - " setting `hf_oauth: true` in the Space metadata." - ) - if constants.OAUTH_CLIENT_ID is None: - raise ValueError(msg.format("OAUTH_CLIENT_ID")) - if constants.OAUTH_CLIENT_SECRET is None: - raise ValueError(msg.format("OAUTH_CLIENT_SECRET")) - if constants.OAUTH_SCOPES is None: - raise ValueError(msg.format("OAUTH_SCOPES")) - if constants.OPENID_PROVIDER_URL is None: - raise ValueError(msg.format("OPENID_PROVIDER_URL")) - - # Register OAuth server - oauth = OAuth() - oauth.register( - name="huggingface", - client_id=constants.OAUTH_CLIENT_ID, - client_secret=constants.OAUTH_CLIENT_SECRET, - client_kwargs={"scope": constants.OAUTH_SCOPES}, - server_metadata_url=constants.OPENID_PROVIDER_URL + "/.well-known/openid-configuration", - ) - - login_uri, callback_uri, logout_uri = _get_oauth_uris(route_prefix) - - # Register OAuth endpoints - @app.get(login_uri) - async def oauth_login(request: fastapi.Request) -> RedirectResponse: - """Endpoint that redirects to HF OAuth page.""" - redirect_uri = _generate_redirect_uri(request) - return await oauth.huggingface.authorize_redirect(request, redirect_uri) # type: ignore - - @app.get(callback_uri) - async def oauth_redirect_callback(request: fastapi.Request) -> RedirectResponse: - """Endpoint that handles the OAuth callback.""" - try: - oauth_info = await oauth.huggingface.authorize_access_token(request) # type: ignore - except MismatchingStateError: - # Parse query params - nb_redirects = int(request.query_params.get("_nb_redirects", 0)) - target_url = request.query_params.get("_target_url") - - # Build redirect URI with the same query params as before and bump nb_redirects count - query_params: dict[str, Union[int, str]] = {"_nb_redirects": nb_redirects + 1} - if target_url: - query_params["_target_url"] = target_url - - redirect_uri = f"{login_uri}?{urllib.parse.urlencode(query_params)}" - - # If the user is redirected more than 3 times, it is very likely that the cookie is not working properly. - # (e.g. browser is blocking third-party cookies in iframe). In this case, redirect the user in the - # non-iframe view. - if nb_redirects > constants.OAUTH_MAX_REDIRECTS: - host = os.environ.get("SPACE_HOST") - if host is None: # cannot happen in a Space - raise RuntimeError( - "App is not running in a Space (SPACE_HOST environment variable is not set). Cannot redirect to non-iframe view." - ) from None - host_url = "https://" + host.rstrip("/") - return RedirectResponse(host_url + redirect_uri) - - # Redirect the user to the login page again - return RedirectResponse(redirect_uri) - - # OAuth login worked => store the user info in the session and redirect - logger.debug("Successfully logged in with OAuth. Storing user info in session.") - request.session["oauth_info"] = oauth_info - return RedirectResponse(_get_redirect_target(request)) - - @app.get(logout_uri) - async def oauth_logout(request: fastapi.Request) -> RedirectResponse: - """Endpoint that logs out the user (e.g. delete info from cookie session).""" - logger.debug("Logged out with OAuth. Removing user info from session.") - request.session.pop("oauth_info", None) - return RedirectResponse(_get_redirect_target(request)) - - -def _add_mocked_oauth_routes(app: "fastapi.FastAPI", route_prefix: str = "/") -> None: - """Add fake oauth routes if app is run locally and OAuth is enabled. - - Using OAuth will have the same behavior as in a Space but instead of authenticating with HF, a mocked user profile - is added to the session. - """ - try: - import fastapi - from fastapi.responses import RedirectResponse - from starlette.datastructures import URL - except ImportError as e: - raise ImportError( - "Cannot initialize OAuth to due a missing library. Please run `pip install huggingface_hub[oauth]` or add " - "`huggingface_hub[oauth]` to your requirements.txt file." - ) from e - - warnings.warn( - "OAuth is not supported outside of a Space environment. To help you debug your app locally, the oauth endpoints" - " are mocked to return your profile and token. To make it work, your machine must be logged in to Huggingface." - ) - mocked_oauth_info = _get_mocked_oauth_info() - - login_uri, callback_uri, logout_uri = _get_oauth_uris(route_prefix) - - # Define OAuth routes - @app.get(login_uri) - async def oauth_login(request: fastapi.Request) -> RedirectResponse: - """Fake endpoint that redirects to HF OAuth page.""" - # Define target (where to redirect after login) - redirect_uri = _generate_redirect_uri(request) - return RedirectResponse(callback_uri + "?" + urllib.parse.urlencode({"_target_url": redirect_uri})) - - @app.get(callback_uri) - async def oauth_redirect_callback(request: fastapi.Request) -> RedirectResponse: - """Endpoint that handles the OAuth callback.""" - request.session["oauth_info"] = mocked_oauth_info - return RedirectResponse(_get_redirect_target(request)) - - @app.get(logout_uri) - async def oauth_logout(request: fastapi.Request) -> RedirectResponse: - """Endpoint that logs out the user (e.g. delete cookie session).""" - request.session.pop("oauth_info", None) - logout_url = URL("/").include_query_params(**request.query_params) - return RedirectResponse(url=logout_url, status_code=302) # see https://github.com/gradio-app/gradio/pull/9659 - - -def _generate_redirect_uri(request: "fastapi.Request") -> str: - if "_target_url" in request.query_params: - # if `_target_url` already in query params => respect it - target = request.query_params["_target_url"] - else: - # otherwise => keep query params - target = "/?" + urllib.parse.urlencode(request.query_params) - - redirect_uri = request.url_for("oauth_redirect_callback").include_query_params(_target_url=target) - redirect_uri_as_str = str(redirect_uri) - if redirect_uri.netloc.endswith(".hf.space"): - # In Space, FastAPI redirect as http but we want https - redirect_uri_as_str = redirect_uri_as_str.replace("http://", "https://") - return redirect_uri_as_str - - -def _get_redirect_target(request: "fastapi.Request", default_target: str = "/") -> str: - return request.query_params.get("_target_url", default_target) - - -def _get_mocked_oauth_info() -> dict: - token = get_token() - if token is None: - raise ValueError( - "Your machine must be logged in to HF to debug an OAuth app locally. Please" - " run `hf auth login` or set `HF_TOKEN` as environment variable " - "with one of your access token. You can generate a new token in your " - "settings page (https://huggingface.co/settings/tokens)." - ) - - user = whoami() - if user["type"] != "user": - raise ValueError( - "Your machine is not logged in with a personal account. Please use a " - "personal access token. You can generate a new token in your settings page" - " (https://huggingface.co/settings/tokens)." - ) - - return { - "access_token": token, - "token_type": "bearer", - "expires_in": 8 * 60 * 60, # 8 hours - "id_token": "FOOBAR", - "scope": "openid profile", - "refresh_token": "hf_oauth__refresh_token", - "expires_at": int(time.time()) + 8 * 60 * 60, # 8 hours - "userinfo": { - "sub": "0123456789", - "name": user["fullname"], - "preferred_username": user["name"], - "profile": f"https://huggingface.co/{user['name']}", - "picture": user["avatarUrl"], - "website": "", - "aud": "00000000-0000-0000-0000-000000000000", - "auth_time": 1691672844, - "nonce": "aaaaaaaaaaaaaaaaaaa", - "iat": 1691672844, - "exp": 1691676444, - "iss": "https://huggingface.co", - }, - } - - -def _get_oauth_uris(route_prefix: str = "/") -> tuple[str, str, str]: - route_prefix = route_prefix.strip("/") - if route_prefix: - route_prefix = f"/{route_prefix}" - return ( - f"{route_prefix}/oauth/huggingface/login", - f"{route_prefix}/oauth/huggingface/callback", - f"{route_prefix}/oauth/huggingface/logout", - ) diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_snapshot_download.py b/venv/lib/python3.10/site-packages/huggingface_hub/_snapshot_download.py deleted file mode 100644 index 59d5fa9239966b1271eac100e005bce3e8c564e7..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_snapshot_download.py +++ /dev/null @@ -1,465 +0,0 @@ -import os -from pathlib import Path -from typing import Iterable, List, Literal, Optional, Union, overload - -import httpx -from tqdm.auto import tqdm as base_tqdm -from tqdm.contrib.concurrent import thread_map - -from . import constants -from .errors import ( - DryRunError, - GatedRepoError, - HfHubHTTPError, - LocalEntryNotFoundError, - RepositoryNotFoundError, - RevisionNotFoundError, -) -from .file_download import REGEX_COMMIT_HASH, DryRunFileInfo, hf_hub_download, repo_folder_name -from .hf_api import DatasetInfo, HfApi, ModelInfo, RepoFile, SpaceInfo -from .utils import OfflineModeIsEnabled, filter_repo_objects, is_tqdm_disabled, logging, validate_hf_hub_args -from .utils import tqdm as hf_tqdm - - -logger = logging.get_logger(__name__) - -LARGE_REPO_THRESHOLD = 1000 # After this limit, we don't consider `repo_info.siblings` to be reliable enough - - -@overload -def snapshot_download( - repo_id: str, - *, - repo_type: Optional[str] = None, - revision: Optional[str] = None, - cache_dir: Union[str, Path, None] = None, - local_dir: Union[str, Path, None] = None, - library_name: Optional[str] = None, - library_version: Optional[str] = None, - user_agent: Optional[Union[dict, str]] = None, - etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT, - force_download: bool = False, - token: Optional[Union[bool, str]] = None, - local_files_only: bool = False, - allow_patterns: Optional[Union[list[str], str]] = None, - ignore_patterns: Optional[Union[list[str], str]] = None, - max_workers: int = 8, - tqdm_class: Optional[type[base_tqdm]] = None, - headers: Optional[dict[str, str]] = None, - endpoint: Optional[str] = None, - dry_run: Literal[False] = False, -) -> str: ... - - -@overload -def snapshot_download( - repo_id: str, - *, - repo_type: Optional[str] = None, - revision: Optional[str] = None, - cache_dir: Union[str, Path, None] = None, - local_dir: Union[str, Path, None] = None, - library_name: Optional[str] = None, - library_version: Optional[str] = None, - user_agent: Optional[Union[dict, str]] = None, - etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT, - force_download: bool = False, - token: Optional[Union[bool, str]] = None, - local_files_only: bool = False, - allow_patterns: Optional[Union[list[str], str]] = None, - ignore_patterns: Optional[Union[list[str], str]] = None, - max_workers: int = 8, - tqdm_class: Optional[type[base_tqdm]] = None, - headers: Optional[dict[str, str]] = None, - endpoint: Optional[str] = None, - dry_run: Literal[True] = True, -) -> list[DryRunFileInfo]: ... - - -@overload -def snapshot_download( - repo_id: str, - *, - repo_type: Optional[str] = None, - revision: Optional[str] = None, - cache_dir: Union[str, Path, None] = None, - local_dir: Union[str, Path, None] = None, - library_name: Optional[str] = None, - library_version: Optional[str] = None, - user_agent: Optional[Union[dict, str]] = None, - etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT, - force_download: bool = False, - token: Optional[Union[bool, str]] = None, - local_files_only: bool = False, - allow_patterns: Optional[Union[list[str], str]] = None, - ignore_patterns: Optional[Union[list[str], str]] = None, - max_workers: int = 8, - tqdm_class: Optional[type[base_tqdm]] = None, - headers: Optional[dict[str, str]] = None, - endpoint: Optional[str] = None, - dry_run: bool = False, -) -> Union[str, list[DryRunFileInfo]]: ... - - -@validate_hf_hub_args -def snapshot_download( - repo_id: str, - *, - repo_type: Optional[str] = None, - revision: Optional[str] = None, - cache_dir: Union[str, Path, None] = None, - local_dir: Union[str, Path, None] = None, - library_name: Optional[str] = None, - library_version: Optional[str] = None, - user_agent: Optional[Union[dict, str]] = None, - etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT, - force_download: bool = False, - token: Optional[Union[bool, str]] = None, - local_files_only: bool = False, - allow_patterns: Optional[Union[list[str], str]] = None, - ignore_patterns: Optional[Union[list[str], str]] = None, - max_workers: int = 8, - tqdm_class: Optional[type[base_tqdm]] = None, - headers: Optional[dict[str, str]] = None, - endpoint: Optional[str] = None, - dry_run: bool = False, -) -> Union[str, list[DryRunFileInfo]]: - """Download repo files. - - Download a whole snapshot of a repo's files at the specified revision. This is useful when you want all files from - a repo, because you don't know which ones you will need a priori. All files are nested inside a folder in order - to keep their actual filename relative to that folder. You can also filter which files to download using - `allow_patterns` and `ignore_patterns`. - - If `local_dir` is provided, the file structure from the repo will be replicated in this location. When using this - option, the `cache_dir` will not be used and a `.cache/huggingface/` folder will be created at the root of `local_dir` - to store some metadata related to the downloaded files. While this mechanism is not as robust as the main - cache-system, it's optimized for regularly pulling the latest version of a repository. - - An alternative would be to clone the repo but this requires git and git-lfs to be installed and properly - configured. It is also not possible to filter which files to download when cloning a repository using git. - - Args: - repo_id (`str`): - A user or an organization name and a repo name separated by a `/`. - repo_type (`str`, *optional*): - Set to `"dataset"` or `"space"` if downloading from a dataset or space, - `None` or `"model"` if downloading from a model. Default is `None`. - revision (`str`, *optional*): - An optional Git revision id which can be a branch name, a tag, or a - commit hash. - cache_dir (`str`, `Path`, *optional*): - Path to the folder where cached files are stored. - local_dir (`str` or `Path`, *optional*): - If provided, the downloaded files will be placed under this directory. - library_name (`str`, *optional*): - The name of the library to which the object corresponds. - library_version (`str`, *optional*): - The version of the library. - user_agent (`str`, `dict`, *optional*): - The user-agent info in the form of a dictionary or a string. - etag_timeout (`float`, *optional*, defaults to `10`): - When fetching ETag, how many seconds to wait for the server to send - data before giving up which is passed to `httpx.request`. - force_download (`bool`, *optional*, defaults to `False`): - Whether the file should be downloaded even if it already exists in the local cache. - token (`str`, `bool`, *optional*): - A token to be used for the download. - - If `True`, the token is read from the HuggingFace config - folder. - - If a string, it's used as the authentication token. - headers (`dict`, *optional*): - Additional headers to include in the request. Those headers take precedence over the others. - local_files_only (`bool`, *optional*, defaults to `False`): - If `True`, avoid downloading the file and return the path to the - local cached file if it exists. - allow_patterns (`list[str]` or `str`, *optional*): - If provided, only files matching at least one pattern are downloaded. - ignore_patterns (`list[str]` or `str`, *optional*): - If provided, files matching any of the patterns are not downloaded. - max_workers (`int`, *optional*): - Number of concurrent threads to download files (1 thread = 1 file download). - Defaults to 8. - tqdm_class (`tqdm`, *optional*): - If provided, overwrites the default behavior for the progress bar. Passed - argument must inherit from `tqdm.auto.tqdm` or at least mimic its behavior. - Note that the `tqdm_class` is not passed to each individual download. - Defaults to the custom HF progress bar that can be disabled by setting - `HF_HUB_DISABLE_PROGRESS_BARS` environment variable. - dry_run (`bool`, *optional*, defaults to `False`): - If `True`, perform a dry run without actually downloading the files. Returns a list of - [`DryRunFileInfo`] objects containing information about what would be downloaded. - - Returns: - `str` or list of [`DryRunFileInfo`]: - - If `dry_run=False`: Local snapshot path. - - If `dry_run=True`: A list of [`DryRunFileInfo`] objects containing download information. - - Raises: - [`~utils.RepositoryNotFoundError`] - If the repository to download from cannot be found. This may be because it doesn't exist, - or because it is set to `private` and you do not have access. - [`~utils.RevisionNotFoundError`] - If the revision to download from cannot be found. - [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError) - If `token=True` and the token cannot be found. - [`OSError`](https://docs.python.org/3/library/exceptions.html#OSError) if - ETag cannot be determined. - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError) - if some parameter value is invalid. - """ - if cache_dir is None: - cache_dir = constants.HF_HUB_CACHE - if revision is None: - revision = constants.DEFAULT_REVISION - if isinstance(cache_dir, Path): - cache_dir = str(cache_dir) - - if repo_type is None: - repo_type = "model" - if repo_type not in constants.REPO_TYPES: - raise ValueError(f"Invalid repo type: {repo_type}. Accepted repo types are: {str(constants.REPO_TYPES)}") - - storage_folder = os.path.join(cache_dir, repo_folder_name(repo_id=repo_id, repo_type=repo_type)) - - api = HfApi( - library_name=library_name, - library_version=library_version, - user_agent=user_agent, - endpoint=endpoint, - headers=headers, - token=token, - ) - - repo_info: Union[ModelInfo, DatasetInfo, SpaceInfo, None] = None - api_call_error: Optional[Exception] = None - if not local_files_only: - # try/except logic to handle different errors => taken from `hf_hub_download` - try: - # if we have internet connection we want to list files to download - repo_info = api.repo_info(repo_id=repo_id, repo_type=repo_type, revision=revision) - except httpx.ProxyError: - # Actually raise on proxy error - raise - except (httpx.ConnectError, httpx.TimeoutException, OfflineModeIsEnabled) as error: - # Internet connection is down - # => will try to use local files only - api_call_error = error - pass - except RevisionNotFoundError: - # The repo was found but the revision doesn't exist on the Hub (never existed or got deleted) - raise - except HfHubHTTPError as error: - # Multiple reasons for an http error: - # - Repository is private and invalid/missing token sent - # - Repository is gated and invalid/missing token sent - # - Hub is down (error 500 or 504) - # => let's switch to 'local_files_only=True' to check if the files are already cached. - # (if it's not the case, the error will be re-raised) - api_call_error = error - pass - - # At this stage, if `repo_info` is None it means either: - # - internet connection is down - # - internet connection is deactivated (local_files_only=True or HF_HUB_OFFLINE=True) - # - repo is private/gated and invalid/missing token sent - # - Hub is down - # => let's look if we can find the appropriate folder in the cache: - # - if the specified revision is a commit hash, look inside "snapshots". - # - f the specified revision is a branch or tag, look inside "refs". - # => if local_dir is not None, we will return the path to the local folder if it exists. - if repo_info is None: - if dry_run: - raise DryRunError( - "Dry run cannot be performed as the repository cannot be accessed. Please check your internet connection or authentication token." - ) from api_call_error - - # Try to get which commit hash corresponds to the specified revision - commit_hash = None - if REGEX_COMMIT_HASH.match(revision): - commit_hash = revision - else: - ref_path = os.path.join(storage_folder, "refs", revision) - if os.path.exists(ref_path): - # retrieve commit_hash from refs file - with open(ref_path) as f: - commit_hash = f.read() - - # Try to locate snapshot folder for this commit hash - if commit_hash is not None and local_dir is None: - snapshot_folder = os.path.join(storage_folder, "snapshots", commit_hash) - if os.path.exists(snapshot_folder): - # Snapshot folder exists => let's return it - # (but we can't check if all the files are actually there) - return snapshot_folder - - # If local_dir is not None, return it if it exists and is not empty - if local_dir is not None: - local_dir = Path(local_dir) - if local_dir.is_dir() and any(local_dir.iterdir()): - logger.warning( - f"Returning existing local_dir `{local_dir}` as remote repo cannot be accessed in `snapshot_download` ({api_call_error})." - ) - return str(local_dir.resolve()) - # If we couldn't find the appropriate folder on disk, raise an error. - if local_files_only: - raise LocalEntryNotFoundError( - "Cannot find an appropriate cached snapshot folder for the specified revision on the local disk and " - "outgoing traffic has been disabled. To enable repo look-ups and downloads online, pass " - "'local_files_only=False' as input." - ) - elif isinstance(api_call_error, OfflineModeIsEnabled): - raise LocalEntryNotFoundError( - "Cannot find an appropriate cached snapshot folder for the specified revision on the local disk and " - "outgoing traffic has been disabled. To enable repo look-ups and downloads online, set " - "'HF_HUB_OFFLINE=0' as environment variable." - ) from api_call_error - elif isinstance(api_call_error, (RepositoryNotFoundError, GatedRepoError)) or ( - isinstance(api_call_error, HfHubHTTPError) and api_call_error.response.status_code == 401 - ): - # Repo not found, gated, or specific authentication error => let's raise the actual error - raise api_call_error - else: - # Otherwise: most likely a connection issue or Hub downtime => let's warn the user - raise LocalEntryNotFoundError( - "An error happened while trying to locate the files on the Hub and we cannot find the appropriate" - " snapshot folder for the specified revision on the local disk. Please check your internet connection" - " and try again." - ) from api_call_error - - # At this stage, internet connection is up and running - # => let's download the files! - assert repo_info.sha is not None, "Repo info returned from server must have a revision sha." - - # Corner case: on very large repos, the siblings list in `repo_info` might not contain all files. - # In that case, we need to use the `list_repo_tree` method to prevent caching issues. - repo_files: Iterable[str] = [f.rfilename for f in repo_info.siblings] if repo_info.siblings is not None else [] - unreliable_nb_files = ( - repo_info.siblings is None or len(repo_info.siblings) == 0 or len(repo_info.siblings) > LARGE_REPO_THRESHOLD - ) - if unreliable_nb_files: - logger.info( - "Number of files in the repo is unreliable. Using `list_repo_tree` to ensure all files are listed." - ) - repo_files = ( - f.rfilename - for f in api.list_repo_tree(repo_id=repo_id, recursive=True, revision=revision, repo_type=repo_type) - if isinstance(f, RepoFile) - ) - - filtered_repo_files: Iterable[str] = filter_repo_objects( - items=repo_files, - allow_patterns=allow_patterns, - ignore_patterns=ignore_patterns, - ) - - if not unreliable_nb_files: - filtered_repo_files = list(filtered_repo_files) - tqdm_desc = f"Fetching {len(filtered_repo_files)} files" - else: - tqdm_desc = "Fetching ... files" - if dry_run: - tqdm_desc = "[dry-run] " + tqdm_desc - - commit_hash = repo_info.sha - snapshot_folder = os.path.join(storage_folder, "snapshots", commit_hash) - # if passed revision is not identical to commit_hash - # then revision has to be a branch name or tag name. - # In that case store a ref. - if revision != commit_hash: - ref_path = os.path.join(storage_folder, "refs", revision) - try: - os.makedirs(os.path.dirname(ref_path), exist_ok=True) - with open(ref_path, "w") as f: - f.write(commit_hash) - except OSError as e: - logger.warning(f"Ignored error while writing commit hash to {ref_path}: {e}.") - - results: List[Union[str, DryRunFileInfo]] = [] - - # User can use its own tqdm class or the default one from `huggingface_hub.utils` - tqdm_class = tqdm_class or hf_tqdm - - # Create a progress bar for the bytes downloaded - # This progress bar is shared across threads/files and gets updated each time we fetch - # metadata for a file. - bytes_progress = tqdm_class( - desc="Downloading (incomplete total...)", - disable=is_tqdm_disabled(log_level=logger.getEffectiveLevel()), - total=0, - initial=0, - unit="B", - unit_scale=True, - name="huggingface_hub.snapshot_download", - ) - - class _AggregatedTqdm: - """Fake tqdm object to aggregate progress into the parent `bytes_progress` bar. - - In practice the `_AggregatedTqdm` object won't be displayed, it's just used to update - the `bytes_progress` bar from each thread/file download. - """ - - def __init__(self, *args, **kwargs): - # Adjust the total of the parent progress bar - total = kwargs.pop("total", None) - if total is not None: - bytes_progress.total += total - bytes_progress.refresh() - - # Adjust initial of the parent progress bar - initial = kwargs.pop("initial", 0) - if initial: - bytes_progress.update(initial) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - pass - - def update(self, n: Optional[Union[int, float]] = 1) -> None: - bytes_progress.update(n) - - # we pass the commit_hash to hf_hub_download - # so no network call happens if we already - # have the file locally. - def _inner_hf_hub_download(repo_file: str) -> None: - results.append( - hf_hub_download( # type: ignore - repo_id, - filename=repo_file, - repo_type=repo_type, - revision=commit_hash, - endpoint=endpoint, - cache_dir=cache_dir, - local_dir=local_dir, - library_name=library_name, - library_version=library_version, - user_agent=user_agent, - etag_timeout=etag_timeout, - force_download=force_download, - token=token, - headers=headers, - tqdm_class=_AggregatedTqdm, # type: ignore - dry_run=dry_run, - ) - ) - - thread_map( - _inner_hf_hub_download, - filtered_repo_files, - desc=tqdm_desc, - max_workers=max_workers, - tqdm_class=tqdm_class, - ) - - bytes_progress.set_description("Download complete") - - if dry_run: - assert all(isinstance(r, DryRunFileInfo) for r in results) - return results # type: ignore - - if local_dir is not None: - return str(os.path.realpath(local_dir)) - return snapshot_folder diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_space_api.py b/venv/lib/python3.10/site-packages/huggingface_hub/_space_api.py deleted file mode 100644 index 4a15e870e4a9e31bb5e53465be759d3367b94600..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_space_api.py +++ /dev/null @@ -1,168 +0,0 @@ -# coding=utf-8 -# Copyright 2019-present, the HuggingFace Inc. team. -# -# 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. -from dataclasses import dataclass -from datetime import datetime -from enum import Enum -from typing import Optional - -from huggingface_hub.utils import parse_datetime - - -class SpaceStage(str, Enum): - """ - Enumeration of possible stage of a Space on the Hub. - - Value can be compared to a string: - ```py - assert SpaceStage.BUILDING == "BUILDING" - ``` - - Taken from https://github.com/huggingface/moon-landing/blob/main/server/repo_types/SpaceInfo.ts#L61 (private url). - """ - - # Copied from moon-landing > server > repo_types > SpaceInfo.ts (private repo) - NO_APP_FILE = "NO_APP_FILE" - CONFIG_ERROR = "CONFIG_ERROR" - BUILDING = "BUILDING" - BUILD_ERROR = "BUILD_ERROR" - RUNNING = "RUNNING" - RUNNING_BUILDING = "RUNNING_BUILDING" - RUNTIME_ERROR = "RUNTIME_ERROR" - DELETING = "DELETING" - STOPPED = "STOPPED" - PAUSED = "PAUSED" - - -class SpaceHardware(str, Enum): - """ - Enumeration of hardwares available to run your Space on the Hub. - - Value can be compared to a string: - ```py - assert SpaceHardware.CPU_BASIC == "cpu-basic" - ``` - - Taken from https://github.com/huggingface-internal/moon-landing/blob/main/server/repo_types/SpaceHardwareFlavor.ts (private url). - """ - - # CPU - CPU_BASIC = "cpu-basic" - CPU_UPGRADE = "cpu-upgrade" - CPU_XL = "cpu-xl" - - # ZeroGPU - ZERO_A10G = "zero-a10g" - - # GPU - T4_SMALL = "t4-small" - T4_MEDIUM = "t4-medium" - L4X1 = "l4x1" - L4X4 = "l4x4" - L40SX1 = "l40sx1" - L40SX4 = "l40sx4" - L40SX8 = "l40sx8" - A10G_SMALL = "a10g-small" - A10G_LARGE = "a10g-large" - A10G_LARGEX2 = "a10g-largex2" - A10G_LARGEX4 = "a10g-largex4" - A100_LARGE = "a100-large" - A100x4 = "a100x4" - A100x8 = "a100x8" - - -class SpaceStorage(str, Enum): - """ - Enumeration of persistent storage available for your Space on the Hub. - - Value can be compared to a string: - ```py - assert SpaceStorage.SMALL == "small" - ``` - - Taken from https://github.com/huggingface/moon-landing/blob/main/server/repo_types/SpaceHardwareFlavor.ts#L24 (private url). - """ - - SMALL = "small" - MEDIUM = "medium" - LARGE = "large" - - -@dataclass -class SpaceRuntime: - """ - Contains information about the current runtime of a Space. - - Args: - stage (`str`): - Current stage of the space. Example: RUNNING. - hardware (`str` or `None`): - Current hardware of the space. Example: "cpu-basic". Can be `None` if Space - is `BUILDING` for the first time. - requested_hardware (`str` or `None`): - Requested hardware. Can be different from `hardware` especially if the request - has just been made. Example: "t4-medium". Can be `None` if no hardware has - been requested yet. - sleep_time (`int` or `None`): - Number of seconds the Space will be kept alive after the last request. By default (if value is `None`), the - Space will never go to sleep if it's running on an upgraded hardware, while it will go to sleep after 48 - hours on a free 'cpu-basic' hardware. For more details, see https://huggingface.co/docs/hub/spaces-gpus#sleep-time. - raw (`dict`): - Raw response from the server. Contains more information about the Space - runtime like number of replicas, number of cpu, memory size,... - """ - - stage: SpaceStage - hardware: Optional[SpaceHardware] - requested_hardware: Optional[SpaceHardware] - sleep_time: Optional[int] - storage: Optional[SpaceStorage] - raw: dict - - def __init__(self, data: dict) -> None: - self.stage = data["stage"] - self.hardware = data.get("hardware", {}).get("current") - self.requested_hardware = data.get("hardware", {}).get("requested") - self.sleep_time = data.get("gcTimeout") - self.storage = data.get("storage") - self.raw = data - - -@dataclass -class SpaceVariable: - """ - Contains information about the current variables of a Space. - - Args: - key (`str`): - Variable key. Example: `"MODEL_REPO_ID"` - value (`str`): - Variable value. Example: `"the_model_repo_id"`. - description (`str` or None): - Description of the variable. Example: `"Model Repo ID of the implemented model"`. - updatedAt (`datetime` or None): - datetime of the last update of the variable (if the variable has been updated at least once). - """ - - key: str - value: str - description: Optional[str] - updated_at: Optional[datetime] - - def __init__(self, key: str, values: dict) -> None: - self.key = key - self.value = values["value"] - self.description = values.get("description") - updated_at = values.get("updatedAt") - self.updated_at = parse_datetime(updated_at) if updated_at is not None else None diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_tensorboard_logger.py b/venv/lib/python3.10/site-packages/huggingface_hub/_tensorboard_logger.py deleted file mode 100644 index 2783a250015afa99fc83e4fcd6484306b54af683..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_tensorboard_logger.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright 2023 The HuggingFace Team. All rights reserved. -# -# 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. -"""Contains a logger to push training logs to the Hub, using Tensorboard.""" - -from pathlib import Path -from typing import Optional, Union - -from ._commit_scheduler import CommitScheduler -from .errors import EntryNotFoundError -from .repocard import ModelCard -from .utils import experimental - - -# Depending on user's setup, SummaryWriter can come either from 'tensorboardX' -# or from 'torch.utils.tensorboard'. Both are compatible so let's try to load -# from either of them. -try: - from tensorboardX import SummaryWriter as _RuntimeSummaryWriter - - is_summary_writer_available = True -except ImportError: - try: - from torch.utils.tensorboard import SummaryWriter as _RuntimeSummaryWriter - - is_summary_writer_available = True - except ImportError: - # Dummy class to avoid failing at import. Will raise on instance creation. - class _DummySummaryWriter: - pass - - _RuntimeSummaryWriter = _DummySummaryWriter # type: ignore[assignment] - is_summary_writer_available = False - - -class HFSummaryWriter(_RuntimeSummaryWriter): - """ - Wrapper around the tensorboard's `SummaryWriter` to push training logs to the Hub. - - Data is logged locally and then pushed to the Hub asynchronously. Pushing data to the Hub is done in a separate - thread to avoid blocking the training script. In particular, if the upload fails for any reason (e.g. a connection - issue), the main script will not be interrupted. Data is automatically pushed to the Hub every `commit_every` - minutes (default to every 5 minutes). - - > [!WARNING] - > `HFSummaryWriter` is experimental. Its API is subject to change in the future without prior notice. - - Args: - repo_id (`str`): - The id of the repo to which the logs will be pushed. - logdir (`str`, *optional*): - The directory where the logs will be written. If not specified, a local directory will be created by the - underlying `SummaryWriter` object. - commit_every (`int` or `float`, *optional*): - The frequency (in minutes) at which the logs will be pushed to the Hub. Defaults to 5 minutes. - squash_history (`bool`, *optional*): - Whether to squash the history of the repo after each commit. Defaults to `False`. Squashing commits is - useful to avoid degraded performances on the repo when it grows too large. - repo_type (`str`, *optional*): - The type of the repo to which the logs will be pushed. Defaults to "model". - repo_revision (`str`, *optional*): - The revision of the repo to which the logs will be pushed. Defaults to "main". - repo_private (`bool`, *optional*): - Whether to make the repo private. If `None` (default), the repo will be public unless the organization's default is private. This value is ignored if the repo already exists. - path_in_repo (`str`, *optional*): - The path to the folder in the repo where the logs will be pushed. Defaults to "tensorboard/". - repo_allow_patterns (`list[str]` or `str`, *optional*): - A list of patterns to include in the upload. Defaults to `"*.tfevents.*"`. Check out the - [upload guide](https://huggingface.co/docs/huggingface_hub/guides/upload#upload-a-folder) for more details. - repo_ignore_patterns (`list[str]` or `str`, *optional*): - A list of patterns to exclude in the upload. Check out the - [upload guide](https://huggingface.co/docs/huggingface_hub/guides/upload#upload-a-folder) for more details. - token (`str`, *optional*): - Authentication token. Will default to the stored token. See https://huggingface.co/settings/token for more - details - kwargs: - Additional keyword arguments passed to `SummaryWriter`. - - Examples: - ```diff - # Taken from https://pytorch.org/docs/stable/tensorboard.html - - from torch.utils.tensorboard import SummaryWriter - + from huggingface_hub import HFSummaryWriter - - import numpy as np - - - writer = SummaryWriter() - + writer = HFSummaryWriter(repo_id="username/my-trained-model") - - for n_iter in range(100): - writer.add_scalar('Loss/train', np.random.random(), n_iter) - writer.add_scalar('Loss/test', np.random.random(), n_iter) - writer.add_scalar('Accuracy/train', np.random.random(), n_iter) - writer.add_scalar('Accuracy/test', np.random.random(), n_iter) - ``` - - ```py - >>> from huggingface_hub import HFSummaryWriter - - # Logs are automatically pushed every 15 minutes (5 by default) + when exiting the context manager - >>> with HFSummaryWriter(repo_id="test_hf_logger", commit_every=15) as logger: - ... logger.add_scalar("a", 1) - ... logger.add_scalar("b", 2) - ``` - """ - - @experimental - def __new__(cls, *args, **kwargs) -> "HFSummaryWriter": - if not is_summary_writer_available: - raise ImportError( - "You must have `tensorboard` installed to use `HFSummaryWriter`. Please run `pip install --upgrade" - " tensorboardX` first." - ) - return super().__new__(cls) - - def __init__( - self, - repo_id: str, - *, - logdir: Optional[str] = None, - commit_every: Union[int, float] = 5, - squash_history: bool = False, - repo_type: Optional[str] = None, - repo_revision: Optional[str] = None, - repo_private: Optional[bool] = None, - path_in_repo: Optional[str] = "tensorboard", - repo_allow_patterns: Optional[Union[list[str], str]] = "*.tfevents.*", - repo_ignore_patterns: Optional[Union[list[str], str]] = None, - token: Optional[str] = None, - **kwargs, - ): - # Initialize SummaryWriter - super().__init__(logdir=logdir, **kwargs) - - # Check logdir has been correctly initialized and fail early otherwise. In practice, SummaryWriter takes care of it. - if not isinstance(self.logdir, str): - raise ValueError(f"`self.logdir` must be a string. Got '{self.logdir}' of type {type(self.logdir)}.") - - # Append logdir name to `path_in_repo` - if path_in_repo is None or path_in_repo == "": - path_in_repo = Path(self.logdir).name - else: - path_in_repo = path_in_repo.strip("/") + "/" + Path(self.logdir).name - - # Initialize scheduler - self.scheduler = CommitScheduler( - folder_path=self.logdir, - path_in_repo=path_in_repo, - repo_id=repo_id, - repo_type=repo_type, - revision=repo_revision, - private=repo_private, - token=token, - allow_patterns=repo_allow_patterns, - ignore_patterns=repo_ignore_patterns, - every=commit_every, - squash_history=squash_history, - ) - - # Exposing some high-level info at root level - self.repo_id = self.scheduler.repo_id - self.repo_type = self.scheduler.repo_type - self.repo_revision = self.scheduler.revision - - # Add `hf-summary-writer` tag to the model card metadata - try: - card = ModelCard.load(repo_id_or_path=self.repo_id, repo_type=self.repo_type) - except EntryNotFoundError: - card = ModelCard("") - tags = card.data.get("tags", []) - if "hf-summary-writer" not in tags: - tags.append("hf-summary-writer") - card.data["tags"] = tags - card.push_to_hub(repo_id=self.repo_id, repo_type=self.repo_type) - - def __exit__(self, exc_type, exc_val, exc_tb): - """Push to hub in a non-blocking way when exiting the logger's context manager.""" - super().__exit__(exc_type, exc_val, exc_tb) - future = self.scheduler.trigger() - future.result() diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_upload_large_folder.py b/venv/lib/python3.10/site-packages/huggingface_hub/_upload_large_folder.py deleted file mode 100644 index a6e269717892c0d6bbdd4fc30bd6705d844dedfd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_upload_large_folder.py +++ /dev/null @@ -1,765 +0,0 @@ -# coding=utf-8 -# Copyright 2024-present, the HuggingFace Inc. team. -# -# 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. -import enum -import logging -import os -import queue -import shutil -import sys -import threading -import time -import traceback -from datetime import datetime -from pathlib import Path -from threading import Lock -from typing import TYPE_CHECKING, Any, Optional, Union -from urllib.parse import quote - -from ._commit_api import CommitOperationAdd, UploadInfo, _fetch_upload_modes -from ._local_folder import LocalUploadFileMetadata, LocalUploadFilePaths, get_local_upload_paths, read_upload_metadata -from .constants import DEFAULT_REVISION, REPO_TYPES -from .utils import DEFAULT_IGNORE_PATTERNS, _format_size, filter_repo_objects, tqdm -from .utils._runtime import is_xet_available -from .utils.sha import sha_fileobj - - -if TYPE_CHECKING: - from .hf_api import HfApi - -logger = logging.getLogger(__name__) - -WAITING_TIME_IF_NO_TASKS = 10 # seconds -MAX_NB_FILES_FETCH_UPLOAD_MODE = 100 -COMMIT_SIZE_SCALE: list[int] = [20, 50, 75, 100, 125, 200, 250, 400, 600, 1000] - -UPLOAD_BATCH_SIZE_XET = 256 # Max 256 files per upload batch for XET-enabled repos -UPLOAD_BATCH_SIZE_LFS = 1 # Otherwise, batches of 1 for regular LFS upload - -# Repository limits (from https://huggingface.co/docs/hub/repositories-recommendations) -MAX_FILES_PER_REPO = 100_000 # Recommended maximum number of files per repository -MAX_FILES_PER_FOLDER = 10_000 # Recommended maximum number of files per folder -MAX_FILE_SIZE_GB = 200 # Recommended maximum for individual file size (split larger files) -RECOMMENDED_FILE_SIZE_GB = 20 # Recommended maximum for individual file size - - -def _validate_upload_limits(paths_list: list[LocalUploadFilePaths]) -> None: - """ - Validate upload against repository limits and warn about potential issues. - - Args: - paths_list: List of file paths to be uploaded - - Warns about: - - Too many files in the repository (>100k) - - Too many entries (files or subdirectories) in a single folder (>10k) - - Files exceeding size limits (>20GB recommended, >200GB maximum) - """ - logger.info("Running validation checks on files to upload...") - - # Check 1: Total file count - if len(paths_list) > MAX_FILES_PER_REPO: - logger.warning( - f"You are about to upload {len(paths_list):,} files. " - f"This exceeds the recommended limit of {MAX_FILES_PER_REPO:,} files per repository.\n" - f"Consider:\n" - f" - Splitting your data into multiple repositories\n" - f" - Using fewer, larger files (e.g., parquet files)\n" - f" - See: https://huggingface.co/docs/hub/repositories-recommendations" - ) - - # Check 2: Files and subdirectories per folder - # Track immediate children (files and subdirs) for each folder - from collections import defaultdict - - entries_per_folder: dict[str, Any] = defaultdict(lambda: {"files": 0, "subdirs": set()}) - - for paths in paths_list: - path = Path(paths.path_in_repo) - parts = path.parts - - # Count this file in its immediate parent directory - parent = str(path.parent) if str(path.parent) != "." else "." - entries_per_folder[parent]["files"] += 1 - - # Track immediate subdirectories for each parent folder - # Walk through the path components to track parent-child relationships - for i, child in enumerate(parts[:-1]): - parent = "." if i == 0 else "/".join(parts[:i]) - entries_per_folder[parent]["subdirs"].add(child) - - # Check limits for each folder - for folder, data in entries_per_folder.items(): - file_count = data["files"] - subdir_count = len(data["subdirs"]) - total_entries = file_count + subdir_count - - if total_entries > MAX_FILES_PER_FOLDER: - folder_display = "root" if folder == "." else folder - logger.warning( - f"Folder '{folder_display}' contains {total_entries:,} entries " - f"({file_count:,} files and {subdir_count:,} subdirectories). " - f"This exceeds the recommended {MAX_FILES_PER_FOLDER:,} entries per folder.\n" - "Consider reorganising into sub-folders." - ) - - # Check 3: File sizes - large_files = [] - very_large_files = [] - - for paths in paths_list: - size = paths.file_path.stat().st_size - size_gb = size / 1_000_000_000 # Use decimal GB as per Hub limits - - if size_gb > MAX_FILE_SIZE_GB: - very_large_files.append((paths.path_in_repo, size_gb)) - elif size_gb > RECOMMENDED_FILE_SIZE_GB: - large_files.append((paths.path_in_repo, size_gb)) - - # Warn about very large files (>200GB) - if very_large_files: - files_str = "\n - ".join(f"{path}: {size:.1f}GB" for path, size in very_large_files[:5]) - more_str = f"\n ... and {len(very_large_files) - 5} more files" if len(very_large_files) > 5 else "" - logger.warning( - f"Found {len(very_large_files)} files exceeding the {MAX_FILE_SIZE_GB}GB recommended maximum:\n" - f" - {files_str}{more_str}\n" - f"Consider splitting these files into smaller chunks." - ) - - # Warn about large files (>20GB) - if large_files: - files_str = "\n - ".join(f"{path}: {size:.1f}GB" for path, size in large_files[:5]) - more_str = f"\n ... and {len(large_files) - 5} more files" if len(large_files) > 5 else "" - logger.warning( - f"Found {len(large_files)} files larger than {RECOMMENDED_FILE_SIZE_GB}GB (recommended limit):\n" - f" - {files_str}{more_str}\n" - f"Large files may slow down loading and processing." - ) - - logger.info("Validation checks complete.") - - -def upload_large_folder_internal( - api: "HfApi", - repo_id: str, - folder_path: Union[str, Path], - *, - repo_type: str, # Repo type is required! - revision: Optional[str] = None, - private: Optional[bool] = None, - allow_patterns: Optional[Union[list[str], str]] = None, - ignore_patterns: Optional[Union[list[str], str]] = None, - num_workers: Optional[int] = None, - print_report: bool = True, - print_report_every: int = 60, -): - """Upload a large folder to the Hub in the most resilient way possible. - - See [`HfApi.upload_large_folder`] for the full documentation. - """ - # 1. Check args and setup - if repo_type is None: - raise ValueError( - "For large uploads, `repo_type` is explicitly required. Please set it to `model`, `dataset` or `space`." - " If you are using the CLI, pass it as `--repo-type=model`." - ) - if repo_type not in REPO_TYPES: - raise ValueError(f"Invalid repo type, must be one of {REPO_TYPES}") - if revision is None: - revision = DEFAULT_REVISION - - folder_path = Path(folder_path).expanduser().resolve() - if not folder_path.is_dir(): - raise ValueError(f"Provided path: '{folder_path}' is not a directory") - - if ignore_patterns is None: - ignore_patterns = [] - elif isinstance(ignore_patterns, str): - ignore_patterns = [ignore_patterns] - ignore_patterns += DEFAULT_IGNORE_PATTERNS - - if num_workers is None: - nb_cores = os.cpu_count() or 1 - num_workers = max(nb_cores // 2, 1) # Use at most half of cpu cores - - # 2. Create repo if missing - repo_url = api.create_repo(repo_id=repo_id, repo_type=repo_type, private=private, exist_ok=True) - logger.info(f"Repo created: {repo_url}") - repo_id = repo_url.repo_id - - # Warn on too many commits - try: - commits = api.list_repo_commits(repo_id=repo_id, repo_type=repo_type, revision=revision) - commit_count = len(commits) - if commit_count > 500: - logger.warning( - f"\n{'=' * 80}\n" - f"WARNING: This repository has {commit_count} commits.\n" - f"Repositories with a large number of commits can experience performance issues.\n" - f"\n" - f"Consider squashing your commit history using `super_squash_history()`.\n" - "To do so, you need to stop this process, run the snippet below and restart the upload command." - f" from huggingface_hub import super_squash_history\n" - f" super_squash_history(repo_id='{repo_id}', repo_type='{repo_type}')\n" - f"\n" - f"Note: This is a non-revertible operation. See the documentation for more details:\n" - f"https://huggingface.co/docs/huggingface_hub/main/en/package_reference/hf_api#huggingface_hub.HfApi.super_squash_history\n" - f"{'=' * 80}\n" - ) - except Exception as e: - # Don't fail the upload if we can't check commit count - logger.debug(f"Could not check commit count: {e}") - - # 2.1 Check if xet is enabled to set batch file upload size - upload_batch_size = UPLOAD_BATCH_SIZE_XET if is_xet_available() else UPLOAD_BATCH_SIZE_LFS - - # 3. List files to upload - filtered_paths_list = filter_repo_objects( - (path.relative_to(folder_path).as_posix() for path in folder_path.glob("**/*") if path.is_file()), - allow_patterns=allow_patterns, - ignore_patterns=ignore_patterns, - ) - paths_list = [get_local_upload_paths(folder_path, relpath) for relpath in filtered_paths_list] - logger.info(f"Found {len(paths_list)} candidate files to upload") - - # Validate upload against repository limits - _validate_upload_limits(paths_list) - - logger.info("Starting upload...") - - # Read metadata for each file - items = [ - (paths, read_upload_metadata(folder_path, paths.path_in_repo)) - for paths in tqdm(paths_list, desc="Recovering from metadata files") - ] - - # 4. Start workers - status = LargeUploadStatus(items, upload_batch_size) - threads = [ - threading.Thread( - target=_worker_job, - kwargs={ - "status": status, - "api": api, - "repo_id": repo_id, - "repo_type": repo_type, - "revision": revision, - }, - ) - for _ in range(num_workers) - ] - - for thread in threads: - thread.start() - - # 5. Print regular reports - if print_report: - print("\n\n" + status.current_report()) - last_report_ts = time.time() - while True: - time.sleep(1) - if time.time() - last_report_ts >= print_report_every: - if print_report: - _print_overwrite(status.current_report()) - last_report_ts = time.time() - if status.is_done(): - logging.info("Is done: exiting main loop") - break - - for thread in threads: - thread.join() - - logger.info(status.current_report()) - logging.info("Upload is complete!") - - -#################### -# Logic to manage workers and synchronize tasks -#################### - - -class WorkerJob(enum.Enum): - SHA256 = enum.auto() - GET_UPLOAD_MODE = enum.auto() - PREUPLOAD_LFS = enum.auto() - COMMIT = enum.auto() - WAIT = enum.auto() # if no tasks are available but we don't want to exit - - -JOB_ITEM_T = tuple[LocalUploadFilePaths, LocalUploadFileMetadata] - - -class LargeUploadStatus: - """Contains information, queues and tasks for a large upload process.""" - - def __init__(self, items: list[JOB_ITEM_T], upload_batch_size: int = 1): - self.items = items - self.queue_sha256: "queue.Queue[JOB_ITEM_T]" = queue.Queue() - self.queue_get_upload_mode: "queue.Queue[JOB_ITEM_T]" = queue.Queue() - self.queue_preupload_lfs: "queue.Queue[JOB_ITEM_T]" = queue.Queue() - self.queue_commit: "queue.Queue[JOB_ITEM_T]" = queue.Queue() - self.lock = Lock() - - self.nb_workers_sha256: int = 0 - self.nb_workers_get_upload_mode: int = 0 - self.nb_workers_preupload_lfs: int = 0 - self.upload_batch_size: int = upload_batch_size - self.nb_workers_commit: int = 0 - self.nb_workers_waiting: int = 0 - self.last_commit_attempt: Optional[float] = None - - self._started_at = datetime.now() - self._chunk_idx: int = 1 - self._chunk_lock: Lock = Lock() - - # Setup queues - for item in self.items: - paths, metadata = item - if metadata.sha256 is None: - self.queue_sha256.put(item) - elif metadata.upload_mode is None: - self.queue_get_upload_mode.put(item) - elif metadata.upload_mode == "lfs" and not metadata.is_uploaded: - self.queue_preupload_lfs.put(item) - elif not metadata.is_committed: - self.queue_commit.put(item) - else: - logger.debug(f"Skipping file {paths.path_in_repo} (already uploaded and committed)") - - def target_chunk(self) -> int: - with self._chunk_lock: - return COMMIT_SIZE_SCALE[self._chunk_idx] - - def update_chunk(self, success: bool, nb_items: int, duration: float) -> None: - with self._chunk_lock: - if not success: - logger.warning(f"Failed to commit {nb_items} files at once. Will retry with less files in next batch.") - self._chunk_idx -= 1 - elif nb_items >= COMMIT_SIZE_SCALE[self._chunk_idx] and duration < 40: - logger.info(f"Successfully committed {nb_items} at once. Increasing the limit for next batch.") - self._chunk_idx += 1 - - self._chunk_idx = max(0, min(self._chunk_idx, len(COMMIT_SIZE_SCALE) - 1)) - - def current_report(self) -> str: - """Generate a report of the current status of the large upload.""" - nb_hashed = 0 - size_hashed = 0 - nb_preuploaded = 0 - nb_lfs = 0 - nb_lfs_unsure = 0 - size_preuploaded = 0 - nb_committed = 0 - size_committed = 0 - total_size = 0 - ignored_files = 0 - total_files = 0 - - with self.lock: - for _, metadata in self.items: - if metadata.should_ignore: - ignored_files += 1 - continue - total_size += metadata.size - total_files += 1 - if metadata.sha256 is not None: - nb_hashed += 1 - size_hashed += metadata.size - if metadata.upload_mode == "lfs": - nb_lfs += 1 - if metadata.upload_mode is None: - nb_lfs_unsure += 1 - if metadata.is_uploaded: - nb_preuploaded += 1 - size_preuploaded += metadata.size - if metadata.is_committed: - nb_committed += 1 - size_committed += metadata.size - total_size_str = _format_size(total_size) - - now = datetime.now() - now_str = now.strftime("%Y-%m-%d %H:%M:%S") - elapsed = now - self._started_at - elapsed_str = str(elapsed).split(".")[0] # remove milliseconds - - message = "\n" + "-" * 10 - message += f" {now_str} ({elapsed_str}) " - message += "-" * 10 + "\n" - - message += "Files: " - message += f"hashed {nb_hashed}/{total_files} ({_format_size(size_hashed)}/{total_size_str}) | " - message += f"pre-uploaded: {nb_preuploaded}/{nb_lfs} ({_format_size(size_preuploaded)}/{total_size_str})" - if nb_lfs_unsure > 0: - message += f" (+{nb_lfs_unsure} unsure)" - message += f" | committed: {nb_committed}/{total_files} ({_format_size(size_committed)}/{total_size_str})" - message += f" | ignored: {ignored_files}\n" - - message += "Workers: " - message += f"hashing: {self.nb_workers_sha256} | " - message += f"get upload mode: {self.nb_workers_get_upload_mode} | " - message += f"pre-uploading: {self.nb_workers_preupload_lfs} | " - message += f"committing: {self.nb_workers_commit} | " - message += f"waiting: {self.nb_workers_waiting}\n" - message += "-" * 51 - - return message - - def is_done(self) -> bool: - with self.lock: - return all(metadata.is_committed or metadata.should_ignore for _, metadata in self.items) - - -def _worker_job( - status: LargeUploadStatus, - api: "HfApi", - repo_id: str, - repo_type: str, - revision: str, -): - """ - Main process for a worker. The worker will perform tasks based on the priority list until all files are uploaded - and committed. If no tasks are available, the worker will wait for 10 seconds before checking again. - - If a task fails for any reason, the item(s) are put back in the queue for another worker to pick up. - - Read `upload_large_folder` docstring for more information on how tasks are prioritized. - """ - while True: - next_job: Optional[tuple[WorkerJob, list[JOB_ITEM_T]]] = None - - # Determine next task - next_job = _determine_next_job(status) - if next_job is None: - return - job, items = next_job - - # Perform task - if job == WorkerJob.SHA256: - item = items[0] # single item - try: - _compute_sha256(item) - status.queue_get_upload_mode.put(item) - except KeyboardInterrupt: - raise - except Exception as e: - logger.error(f"Failed to compute sha256: {e}") - traceback.format_exc() - status.queue_sha256.put(item) - - with status.lock: - status.nb_workers_sha256 -= 1 - - elif job == WorkerJob.GET_UPLOAD_MODE: - try: - _get_upload_mode(items, api=api, repo_id=repo_id, repo_type=repo_type, revision=revision) - except KeyboardInterrupt: - raise - except Exception as e: - logger.error(f"Failed to get upload mode: {e}") - traceback.format_exc() - - # Items are either: - # - dropped (if should_ignore) - # - put in LFS queue (if LFS) - # - put in commit queue (if regular) - # - or put back (if error occurred). - for item in items: - _, metadata = item - if metadata.should_ignore: - continue - if metadata.upload_mode == "lfs": - status.queue_preupload_lfs.put(item) - elif metadata.upload_mode == "regular": - status.queue_commit.put(item) - else: - status.queue_get_upload_mode.put(item) - - with status.lock: - status.nb_workers_get_upload_mode -= 1 - - elif job == WorkerJob.PREUPLOAD_LFS: - try: - _preupload_lfs(items, api=api, repo_id=repo_id, repo_type=repo_type, revision=revision) - for item in items: - status.queue_commit.put(item) - except KeyboardInterrupt: - raise - except Exception as e: - logger.error(f"Failed to preupload LFS: {e}") - traceback.format_exc() - for item in items: - status.queue_preupload_lfs.put(item) - - with status.lock: - status.nb_workers_preupload_lfs -= 1 - - elif job == WorkerJob.COMMIT: - start_ts = time.time() - success = True - try: - _commit(items, api=api, repo_id=repo_id, repo_type=repo_type, revision=revision) - except KeyboardInterrupt: - raise - except Exception as e: - logger.error(f"Failed to commit: {e}") - traceback.format_exc() - for item in items: - status.queue_commit.put(item) - success = False - duration = time.time() - start_ts - status.update_chunk(success, len(items), duration) - with status.lock: - status.last_commit_attempt = time.time() - status.nb_workers_commit -= 1 - - elif job == WorkerJob.WAIT: - time.sleep(WAITING_TIME_IF_NO_TASKS) - with status.lock: - status.nb_workers_waiting -= 1 - - -def _determine_next_job(status: LargeUploadStatus) -> Optional[tuple[WorkerJob, list[JOB_ITEM_T]]]: - with status.lock: - # 1. Commit if more than 5 minutes since last commit attempt (and at least 1 file) - if ( - status.nb_workers_commit == 0 - and status.queue_commit.qsize() > 0 - and status.last_commit_attempt is not None - and time.time() - status.last_commit_attempt > 5 * 60 - ): - status.nb_workers_commit += 1 - logger.debug("Job: commit (more than 5 minutes since last commit attempt)") - return (WorkerJob.COMMIT, _get_n(status.queue_commit, status.target_chunk())) - - # 2. Commit if at least 100 files are ready to commit - elif status.nb_workers_commit == 0 and status.queue_commit.qsize() >= 150: - status.nb_workers_commit += 1 - logger.debug("Job: commit (>100 files ready)") - return (WorkerJob.COMMIT, _get_n(status.queue_commit, status.target_chunk())) - - # 3. Get upload mode if at least 100 files - elif status.queue_get_upload_mode.qsize() >= MAX_NB_FILES_FETCH_UPLOAD_MODE: - status.nb_workers_get_upload_mode += 1 - logger.debug(f"Job: get upload mode (>{MAX_NB_FILES_FETCH_UPLOAD_MODE} files ready)") - return (WorkerJob.GET_UPLOAD_MODE, _get_n(status.queue_get_upload_mode, MAX_NB_FILES_FETCH_UPLOAD_MODE)) - - # 4. Preupload LFS file if at least `status.upload_batch_size` files and no worker is preuploading LFS - elif status.queue_preupload_lfs.qsize() >= status.upload_batch_size and status.nb_workers_preupload_lfs == 0: - status.nb_workers_preupload_lfs += 1 - logger.debug("Job: preupload LFS (no other worker preuploading LFS)") - return (WorkerJob.PREUPLOAD_LFS, _get_n(status.queue_preupload_lfs, status.upload_batch_size)) - - # 5. Compute sha256 if at least 1 file and no worker is computing sha256 - elif status.queue_sha256.qsize() > 0 and status.nb_workers_sha256 == 0: - status.nb_workers_sha256 += 1 - logger.debug("Job: sha256 (no other worker computing sha256)") - return (WorkerJob.SHA256, _get_one(status.queue_sha256)) - - # 6. Get upload mode if at least 1 file and no worker is getting upload mode - elif status.queue_get_upload_mode.qsize() > 0 and status.nb_workers_get_upload_mode == 0: - status.nb_workers_get_upload_mode += 1 - logger.debug("Job: get upload mode (no other worker getting upload mode)") - return (WorkerJob.GET_UPLOAD_MODE, _get_n(status.queue_get_upload_mode, MAX_NB_FILES_FETCH_UPLOAD_MODE)) - - # 7. Preupload LFS file if at least `status.upload_batch_size` files - elif status.queue_preupload_lfs.qsize() >= status.upload_batch_size: - status.nb_workers_preupload_lfs += 1 - logger.debug("Job: preupload LFS") - return (WorkerJob.PREUPLOAD_LFS, _get_n(status.queue_preupload_lfs, status.upload_batch_size)) - - # 8. Compute sha256 if at least 1 file - elif status.queue_sha256.qsize() > 0: - status.nb_workers_sha256 += 1 - logger.debug("Job: sha256") - return (WorkerJob.SHA256, _get_one(status.queue_sha256)) - - # 9. Get upload mode if at least 1 file - elif status.queue_get_upload_mode.qsize() > 0: - status.nb_workers_get_upload_mode += 1 - logger.debug("Job: get upload mode") - return (WorkerJob.GET_UPLOAD_MODE, _get_n(status.queue_get_upload_mode, MAX_NB_FILES_FETCH_UPLOAD_MODE)) - - # 10. Preupload LFS file if at least 1 file - elif status.queue_preupload_lfs.qsize() > 0: - status.nb_workers_preupload_lfs += 1 - logger.debug("Job: preupload LFS") - return (WorkerJob.PREUPLOAD_LFS, _get_n(status.queue_preupload_lfs, status.upload_batch_size)) - - # 11. Commit if at least 1 file and 1 min since last commit attempt - elif ( - status.nb_workers_commit == 0 - and status.queue_commit.qsize() > 0 - and status.last_commit_attempt is not None - and time.time() - status.last_commit_attempt > 1 * 60 - ): - status.nb_workers_commit += 1 - logger.debug("Job: commit (1 min since last commit attempt)") - return (WorkerJob.COMMIT, _get_n(status.queue_commit, status.target_chunk())) - - # 12. Commit if at least 1 file all other queues are empty and all workers are waiting - # e.g. when it's the last commit - elif ( - status.nb_workers_commit == 0 - and status.queue_commit.qsize() > 0 - and status.queue_sha256.qsize() == 0 - and status.queue_get_upload_mode.qsize() == 0 - and status.queue_preupload_lfs.qsize() == 0 - and status.nb_workers_sha256 == 0 - and status.nb_workers_get_upload_mode == 0 - and status.nb_workers_preupload_lfs == 0 - ): - status.nb_workers_commit += 1 - logger.debug("Job: commit") - return (WorkerJob.COMMIT, _get_n(status.queue_commit, status.target_chunk())) - - # 13. If all queues are empty, exit - elif all(metadata.is_committed or metadata.should_ignore for _, metadata in status.items): - logger.info("All files have been processed! Exiting worker.") - return None - - # 14. If no task is available, wait - else: - status.nb_workers_waiting += 1 - logger.debug(f"No task available, waiting... ({WAITING_TIME_IF_NO_TASKS}s)") - return (WorkerJob.WAIT, []) - - -#################### -# Atomic jobs (sha256, get_upload_mode, preupload_lfs, commit) -#################### - - -def _compute_sha256(item: JOB_ITEM_T) -> None: - """Compute sha256 of a file and save it in metadata.""" - paths, metadata = item - if metadata.sha256 is None: - with paths.file_path.open("rb") as f: - metadata.sha256 = sha_fileobj(f).hex() - metadata.save(paths) - - -def _get_upload_mode(items: list[JOB_ITEM_T], api: "HfApi", repo_id: str, repo_type: str, revision: str) -> None: - """Get upload mode for each file and update metadata. - - Also receive info if the file should be ignored. - """ - additions = [_build_hacky_operation(item) for item in items] - _fetch_upload_modes( - additions=additions, - repo_type=repo_type, - repo_id=repo_id, - headers=api._build_hf_headers(), - revision=quote(revision, safe=""), - endpoint=api.endpoint, - ) - for item, addition in zip(items, additions): - paths, metadata = item - metadata.upload_mode = addition._upload_mode - metadata.should_ignore = addition._should_ignore - metadata.remote_oid = addition._remote_oid - metadata.save(paths) - - -def _preupload_lfs(items: list[JOB_ITEM_T], api: "HfApi", repo_id: str, repo_type: str, revision: str) -> None: - """Preupload LFS files and update metadata.""" - additions = [_build_hacky_operation(item) for item in items] - api.preupload_lfs_files( - repo_id=repo_id, - repo_type=repo_type, - revision=revision, - additions=additions, - ) - - for paths, metadata in items: - metadata.is_uploaded = True - metadata.save(paths) - - -def _commit(items: list[JOB_ITEM_T], api: "HfApi", repo_id: str, repo_type: str, revision: str) -> None: - """Commit files to the repo.""" - additions = [_build_hacky_operation(item) for item in items] - api.create_commit( - repo_id=repo_id, - repo_type=repo_type, - revision=revision, - operations=additions, - commit_message="Add files using upload-large-folder tool", - ) - for paths, metadata in items: - metadata.is_committed = True - metadata.save(paths) - - -#################### -# Hacks with CommitOperationAdd to bypass checks/sha256 calculation -#################### - - -class HackyCommitOperationAdd(CommitOperationAdd): - def __post_init__(self) -> None: - if isinstance(self.path_or_fileobj, Path): - self.path_or_fileobj = str(self.path_or_fileobj) - - -def _build_hacky_operation(item: JOB_ITEM_T) -> HackyCommitOperationAdd: - paths, metadata = item - operation = HackyCommitOperationAdd(path_in_repo=paths.path_in_repo, path_or_fileobj=paths.file_path) - with paths.file_path.open("rb") as file: - sample = file.peek(512)[:512] - if metadata.sha256 is None: - raise ValueError("sha256 must have been computed by now!") - operation.upload_info = UploadInfo(sha256=bytes.fromhex(metadata.sha256), size=metadata.size, sample=sample) - operation._upload_mode = metadata.upload_mode # type: ignore[assignment] - operation._should_ignore = metadata.should_ignore - operation._remote_oid = metadata.remote_oid - return operation - - -#################### -# Misc helpers -#################### - - -def _get_one(queue: "queue.Queue[JOB_ITEM_T]") -> list[JOB_ITEM_T]: - return [queue.get()] - - -def _get_n(queue: "queue.Queue[JOB_ITEM_T]", n: int) -> list[JOB_ITEM_T]: - return [queue.get() for _ in range(min(queue.qsize(), n))] - - -def _print_overwrite(report: str) -> None: - """Print a report, overwriting the previous lines. - - Since tqdm in using `sys.stderr` to (re-)write progress bars, we need to use `sys.stdout` - to print the report. - - Note: works well only if no other process is writing to `sys.stdout`! - """ - report += "\n" - # Get terminal width - terminal_width = shutil.get_terminal_size().columns - - # Count number of lines that should be cleared - nb_lines = sum(len(line) // terminal_width + 1 for line in report.splitlines()) - - # Clear previous lines based on the number of lines in the report - for _ in range(nb_lines): - sys.stdout.write("\r\033[K") # Clear line - sys.stdout.write("\033[F") # Move cursor up one line - - # Print the new report, filling remaining space with whitespace - sys.stdout.write(report) - sys.stdout.write(" " * (terminal_width - len(report.splitlines()[-1]))) - sys.stdout.flush() diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_webhooks_payload.py b/venv/lib/python3.10/site-packages/huggingface_hub/_webhooks_payload.py deleted file mode 100644 index 90f12425cbbf4a8fb279ee6b3fe7f594be88a8b1..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_webhooks_payload.py +++ /dev/null @@ -1,137 +0,0 @@ -# coding=utf-8 -# Copyright 2023-present, the HuggingFace Inc. team. -# -# 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. -"""Contains data structures to parse the webhooks payload.""" - -from typing import Literal, Optional - -from .utils import is_pydantic_available - - -if is_pydantic_available(): - from pydantic import BaseModel -else: - # Define a dummy BaseModel to avoid import errors when pydantic is not installed - # Import error will be raised when trying to use the class - - class BaseModel: # type: ignore [no-redef] - def __init__(self, *args, **kwargs) -> None: - raise ImportError( - "You must have `pydantic` installed to use `WebhookPayload`. This is an optional dependency that" - " should be installed separately. Please run `pip install --upgrade pydantic` and retry." - ) - - -# This is an adaptation of the ReportV3 interface implemented in moon-landing. V0, V1 and V2 have been ignored as they -# are not in used anymore. To keep in sync when format is updated in -# https://github.com/huggingface/moon-landing/blob/main/server/lib/HFWebhooks.ts (internal link). - - -WebhookEvent_T = Literal[ - "create", - "delete", - "move", - "update", -] -RepoChangeEvent_T = Literal[ - "add", - "move", - "remove", - "update", -] -RepoType_T = Literal[ - "dataset", - "model", - "space", -] -DiscussionStatus_T = Literal[ - "closed", - "draft", - "open", - "merged", -] -SupportedWebhookVersion = Literal[3] - - -class ObjectId(BaseModel): - id: str - - -class WebhookPayloadUrl(BaseModel): - web: str - api: Optional[str] = None - - -class WebhookPayloadMovedTo(BaseModel): - name: str - owner: ObjectId - - -class WebhookPayloadWebhook(ObjectId): - version: SupportedWebhookVersion - - -class WebhookPayloadEvent(BaseModel): - action: WebhookEvent_T - scope: str - - -class WebhookPayloadDiscussionChanges(BaseModel): - base: str - mergeCommitId: Optional[str] = None - - -class WebhookPayloadComment(ObjectId): - author: ObjectId - hidden: bool - content: Optional[str] = None - url: WebhookPayloadUrl - - -class WebhookPayloadDiscussion(ObjectId): - num: int - author: ObjectId - url: WebhookPayloadUrl - title: str - isPullRequest: bool - status: DiscussionStatus_T - changes: Optional[WebhookPayloadDiscussionChanges] = None - pinned: Optional[bool] = None - - -class WebhookPayloadRepo(ObjectId): - owner: ObjectId - head_sha: Optional[str] = None - name: str - private: bool - subdomain: Optional[str] = None - tags: Optional[list[str]] = None - type: Literal["dataset", "model", "space"] - url: WebhookPayloadUrl - - -class WebhookPayloadUpdatedRef(BaseModel): - ref: str - oldSha: Optional[str] = None - newSha: Optional[str] = None - - -class WebhookPayload(BaseModel): - event: WebhookPayloadEvent - repo: WebhookPayloadRepo - discussion: Optional[WebhookPayloadDiscussion] = None - comment: Optional[WebhookPayloadComment] = None - webhook: WebhookPayloadWebhook - movedTo: Optional[WebhookPayloadMovedTo] = None - updatedRefs: Optional[list[WebhookPayloadUpdatedRef]] = None diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/_webhooks_server.py b/venv/lib/python3.10/site-packages/huggingface_hub/_webhooks_server.py deleted file mode 100644 index 601a55c3d2801964d4fb2172e18e7149d33cc0b2..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/_webhooks_server.py +++ /dev/null @@ -1,376 +0,0 @@ -# coding=utf-8 -# Copyright 2023-present, the HuggingFace Inc. team. -# -# 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. -"""Contains `WebhooksServer` and `webhook_endpoint` to create a webhook server easily.""" - -import atexit -import inspect -import os -from functools import wraps -from typing import TYPE_CHECKING, Any, Callable, Optional - -from .utils import experimental, is_fastapi_available, is_gradio_available - - -if TYPE_CHECKING: - import gradio as gr - from fastapi import Request - -if is_fastapi_available(): - from fastapi import FastAPI, Request - from fastapi.responses import JSONResponse -else: - # Will fail at runtime if FastAPI is not available - FastAPI = Request = JSONResponse = None # type: ignore - - -_global_app: Optional["WebhooksServer"] = None -_is_local = os.environ.get("SPACE_ID") is None - - -@experimental -class WebhooksServer: - """ - The [`WebhooksServer`] class lets you create an instance of a Gradio app that can receive Huggingface webhooks. - These webhooks can be registered using the [`~WebhooksServer.add_webhook`] decorator. Webhook endpoints are added to - the app as a POST endpoint to the FastAPI router. Once all the webhooks are registered, the `launch` method has to be - called to start the app. - - It is recommended to accept [`WebhookPayload`] as the first argument of the webhook function. It is a Pydantic - model that contains all the information about the webhook event. The data will be parsed automatically for you. - - Check out the [webhooks guide](../guides/webhooks_server) for a step-by-step tutorial on how to set up your - WebhooksServer and deploy it on a Space. - - > [!WARNING] - > `WebhooksServer` is experimental. Its API is subject to change in the future. - - > [!WARNING] - > You must have `gradio` installed to use `WebhooksServer` (`pip install --upgrade gradio`). - - Args: - ui (`gradio.Blocks`, optional): - A Gradio UI instance to be used as the Space landing page. If `None`, a UI displaying instructions - about the configured webhooks is created. - webhook_secret (`str`, optional): - A secret key to verify incoming webhook requests. You can set this value to any secret you want as long as - you also configure it in your [webhooks settings panel](https://huggingface.co/settings/webhooks). You - can also set this value as the `WEBHOOK_SECRET` environment variable. If no secret is provided, the - webhook endpoints are opened without any security. - - Example: - - ```python - import gradio as gr - from huggingface_hub import WebhooksServer, WebhookPayload - - with gr.Blocks() as ui: - ... - - app = WebhooksServer(ui=ui, webhook_secret="my_secret_key") - - @app.add_webhook("/say_hello") - async def hello(payload: WebhookPayload): - return {"message": "hello"} - - app.launch() - ``` - """ - - def __new__(cls, *args, **kwargs) -> "WebhooksServer": - if not is_gradio_available(): - raise ImportError( - "You must have `gradio` installed to use `WebhooksServer`. Please run `pip install --upgrade gradio`" - " first." - ) - if not is_fastapi_available(): - raise ImportError( - "You must have `fastapi` installed to use `WebhooksServer`. Please run `pip install --upgrade fastapi`" - " first." - ) - return super().__new__(cls) - - def __init__( - self, - ui: Optional["gr.Blocks"] = None, - webhook_secret: Optional[str] = None, - ) -> None: - self._ui = ui - - self.webhook_secret = webhook_secret or os.getenv("WEBHOOK_SECRET") - self.registered_webhooks: dict[str, Callable] = {} - _warn_on_empty_secret(self.webhook_secret) - - def add_webhook(self, path: Optional[str] = None) -> Callable: - """ - Decorator to add a webhook to the [`WebhooksServer`] server. - - Args: - path (`str`, optional): - The URL path to register the webhook function. If not provided, the function name will be used as the - path. In any case, all webhooks are registered under `/webhooks`. - - Raises: - ValueError: If the provided path is already registered as a webhook. - - Example: - ```python - from huggingface_hub import WebhooksServer, WebhookPayload - - app = WebhooksServer() - - @app.add_webhook - async def trigger_training(payload: WebhookPayload): - if payload.repo.type == "dataset" and payload.event.action == "update": - # Trigger a training job if a dataset is updated - ... - - app.launch() - ``` - """ - # Usage: directly as decorator. Example: `@app.add_webhook` - if callable(path): - # If path is a function, it means it was used as a decorator without arguments - return self.add_webhook()(path) - - # Usage: provide a path. Example: `@app.add_webhook(...)` - @wraps(FastAPI.post) - def _inner_post(*args, **kwargs): - func = args[0] - abs_path = f"/webhooks/{(path or func.__name__).strip('/')}" - if abs_path in self.registered_webhooks: - raise ValueError(f"Webhook {abs_path} already exists.") - self.registered_webhooks[abs_path] = func - - return _inner_post - - def launch(self, prevent_thread_lock: bool = False, **launch_kwargs: Any) -> None: - """Launch the Gradio app and register webhooks to the underlying FastAPI server. - - Input parameters are forwarded to Gradio when launching the app. - """ - ui = self._ui or self._get_default_ui() - - # Start Gradio App - # - as non-blocking so that webhooks can be added afterwards - # - as shared if launch locally (to debug webhooks) - launch_kwargs.setdefault("share", _is_local) - self.fastapi_app, _, _ = ui.launch(prevent_thread_lock=True, **launch_kwargs) - - # Register webhooks to FastAPI app - for path, func in self.registered_webhooks.items(): - # Add secret check if required - if self.webhook_secret is not None: - func = _wrap_webhook_to_check_secret(func, webhook_secret=self.webhook_secret) - - # Add route to FastAPI app - self.fastapi_app.post(path)(func) - - # Print instructions and block main thread - space_host = os.environ.get("SPACE_HOST") - url = "https://" + space_host if space_host is not None else (ui.share_url or ui.local_url) - if url is None: - raise ValueError("Cannot find the URL of the app. Please provide a valid `ui` or update `gradio` version.") - url = url.strip("/") - message = "\nWebhooks are correctly setup and ready to use:" - message += "\n" + "\n".join(f" - POST {url}{webhook}" for webhook in self.registered_webhooks) - message += "\nGo to https://huggingface.co/settings/webhooks to setup your webhooks." - print(message) - - if not prevent_thread_lock: - ui.block_thread() - - def _get_default_ui(self) -> "gr.Blocks": - """Default UI if not provided (lists webhooks and provides basic instructions).""" - import gradio as gr - - with gr.Blocks() as ui: - gr.Markdown("# This is an app to process 🤗 Webhooks") - gr.Markdown( - "Webhooks are a foundation for MLOps-related features. They allow you to listen for new changes on" - " specific repos or to all repos belonging to particular set of users/organizations (not just your" - " repos, but any repo). Check out this [guide](https://huggingface.co/docs/hub/webhooks) to get to" - " know more about webhooks on the Huggingface Hub." - ) - gr.Markdown( - f"{len(self.registered_webhooks)} webhook(s) are registered:" - + "\n\n" - + "\n ".join( - f"- [{webhook_path}]({_get_webhook_doc_url(webhook.__name__, webhook_path)})" - for webhook_path, webhook in self.registered_webhooks.items() - ) - ) - gr.Markdown( - "Go to https://huggingface.co/settings/webhooks to setup your webhooks." - + "\nYou app is running locally. Please look at the logs to check the full URL you need to set." - if _is_local - else ( - "\nThis app is running on a Space. You can find the corresponding URL in the options menu" - " (top-right) > 'Embed the Space'. The URL looks like 'https://{username}-{repo_name}.hf.space'." - ) - ) - return ui - - -@experimental -def webhook_endpoint(path: Optional[str] = None) -> Callable: - """Decorator to start a [`WebhooksServer`] and register the decorated function as a webhook endpoint. - - This is a helper to get started quickly. If you need more flexibility (custom landing page or webhook secret), - you can use [`WebhooksServer`] directly. You can register multiple webhook endpoints (to the same server) by using - this decorator multiple times. - - Check out the [webhooks guide](../guides/webhooks_server) for a step-by-step tutorial on how to set up your - server and deploy it on a Space. - - > [!WARNING] - > `webhook_endpoint` is experimental. Its API is subject to change in the future. - - > [!WARNING] - > You must have `gradio` installed to use `webhook_endpoint` (`pip install --upgrade gradio`). - - Args: - path (`str`, optional): - The URL path to register the webhook function. If not provided, the function name will be used as the path. - In any case, all webhooks are registered under `/webhooks`. - - Examples: - The default usage is to register a function as a webhook endpoint. The function name will be used as the path. - The server will be started automatically at exit (i.e. at the end of the script). - - ```python - from huggingface_hub import webhook_endpoint, WebhookPayload - - @webhook_endpoint - async def trigger_training(payload: WebhookPayload): - if payload.repo.type == "dataset" and payload.event.action == "update": - # Trigger a training job if a dataset is updated - ... - - # Server is automatically started at the end of the script. - ``` - - Advanced usage: register a function as a webhook endpoint and start the server manually. This is useful if you - are running it in a notebook. - - ```python - from huggingface_hub import webhook_endpoint, WebhookPayload - - @webhook_endpoint - async def trigger_training(payload: WebhookPayload): - if payload.repo.type == "dataset" and payload.event.action == "update": - # Trigger a training job if a dataset is updated - ... - - # Start the server manually - trigger_training.launch() - ``` - """ - if callable(path): - # If path is a function, it means it was used as a decorator without arguments - return webhook_endpoint()(path) - - @wraps(WebhooksServer.add_webhook) - def _inner(func: Callable) -> Callable: - app = _get_global_app() - app.add_webhook(path)(func) - if len(app.registered_webhooks) == 1: - # Register `app.launch` to run at exit (only once) - atexit.register(app.launch) - - @wraps(app.launch) - def _launch_now(): - # Run the app directly (without waiting atexit) - atexit.unregister(app.launch) - app.launch() - - func.launch = _launch_now # type: ignore - return func - - return _inner - - -def _get_global_app() -> WebhooksServer: - global _global_app - if _global_app is None: - _global_app = WebhooksServer() - return _global_app - - -def _warn_on_empty_secret(webhook_secret: Optional[str]) -> None: - if webhook_secret is None: - print("Webhook secret is not defined. This means your webhook endpoints will be open to everyone.") - print( - "To add a secret, set `WEBHOOK_SECRET` as environment variable or pass it at initialization: " - "\n\t`app = WebhooksServer(webhook_secret='my_secret', ...)`" - ) - print( - "For more details about webhook secrets, please refer to" - " https://huggingface.co/docs/hub/webhooks#webhook-secret." - ) - else: - print("Webhook secret is correctly defined.") - - -def _get_webhook_doc_url(webhook_name: str, webhook_path: str) -> str: - """Returns the anchor to a given webhook in the docs (experimental)""" - return "/docs#/default/" + webhook_name + webhook_path.replace("/", "_") + "_post" - - -def _wrap_webhook_to_check_secret(func: Callable, webhook_secret: str) -> Callable: - """Wraps a webhook function to check the webhook secret before calling the function. - - This is a hacky way to add the `request` parameter to the function signature. Since FastAPI based itself on route - parameters to inject the values to the function, we need to hack the function signature to retrieve the `Request` - object (and hence the headers). A far cleaner solution would be to use a middleware. However, since - `fastapi==0.90.1`, a middleware cannot be added once the app has started. And since the FastAPI app is started by - Gradio internals (and not by us), we cannot add a middleware. - - This method is called only when a secret has been defined by the user. If a request is sent without the - "x-webhook-secret", the function will return a 401 error (unauthorized). If the header is sent but is incorrect, - the function will return a 403 error (forbidden). - - Inspired by https://stackoverflow.com/a/33112180. - """ - initial_sig = inspect.signature(func) - - @wraps(func) - async def _protected_func(request: Request, **kwargs): - request_secret = request.headers.get("x-webhook-secret") - if request_secret is None: - return JSONResponse({"error": "x-webhook-secret header not set."}, status_code=401) - if request_secret != webhook_secret: - return JSONResponse({"error": "Invalid webhook secret."}, status_code=403) - - # Inject `request` in kwargs if required - if "request" in initial_sig.parameters: - kwargs["request"] = request - - # Handle both sync and async routes - if inspect.iscoroutinefunction(func): - return await func(**kwargs) - else: - return func(**kwargs) - - # Update signature to include request - if "request" not in initial_sig.parameters: - _protected_func.__signature__ = initial_sig.replace( # type: ignore - parameters=( - inspect.Parameter(name="request", kind=inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=Request), - ) - + tuple(initial_sig.parameters.values()) - ) - - # Return protected route - return _protected_func diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__init__.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__init__.py deleted file mode 100644 index 8568c82be1c638c0ccd34d460fd8b0f73dcbec4e..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2025 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/__init__.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index ebcba801800a7bed75ce190b857d0a190415f838..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/__init__.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/_cli_utils.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/_cli_utils.cpython-310.pyc deleted file mode 100644 index d8aaf162de14be127677139b94be8b29b0512470..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/_cli_utils.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/_errors.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/_errors.cpython-310.pyc deleted file mode 100644 index a139a118cf9e81a35c4f246eac31a5a0bfdc8ed3..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/_errors.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/auth.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/auth.cpython-310.pyc deleted file mode 100644 index 21bf4fce1e008e91fe2f60cfc2d3f0007b47f8b3..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/auth.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/cache.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/cache.cpython-310.pyc deleted file mode 100644 index 584fa90170195de5e0218ee3790db67cab821866..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/cache.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/collections.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/collections.cpython-310.pyc deleted file mode 100644 index 0e1701b59269e36a25b6fba832cd844d3f2e4cee..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/collections.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/datasets.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/datasets.cpython-310.pyc deleted file mode 100644 index 200907481458aa33c484910c91ef06888fd02a1d..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/datasets.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/download.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/download.cpython-310.pyc deleted file mode 100644 index 68a44b97c1f84e289065c6c42ed55650336f34cc..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/download.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/hf.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/hf.cpython-310.pyc deleted file mode 100644 index 2270af6c92576f722291f31e24c3e87f68445cb3..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/hf.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/inference_endpoints.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/inference_endpoints.cpython-310.pyc deleted file mode 100644 index c3643ec01566f3c524a06e03cf4da01fc5bdf815..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/inference_endpoints.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/jobs.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/jobs.cpython-310.pyc deleted file mode 100644 index f4008a7ea1f0bfdf1191cd20f561ed81e6559cb4..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/jobs.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/lfs.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/lfs.cpython-310.pyc deleted file mode 100644 index bd0bea8b7299855a2a015faa5dfc68861a39977a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/lfs.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/models.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/models.cpython-310.pyc deleted file mode 100644 index f57563e54c2e268e218c9f8716f844343e3b62c0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/models.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/papers.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/papers.cpython-310.pyc deleted file mode 100644 index 81d6bba441d4ab57f2d5afee5f5791d404d2b03f..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/papers.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/repo.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/repo.cpython-310.pyc deleted file mode 100644 index fbac77185b67e0ed1b45630fc67b4ab2ae6c6bca..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/repo.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/repo_files.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/repo_files.cpython-310.pyc deleted file mode 100644 index 158868feb0fcec0f46c8cb15b8ede941a66ae1be..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/repo_files.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/skills.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/skills.cpython-310.pyc deleted file mode 100644 index 68a214eb6fc55635965d8584c0d8c42627e476a9..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/skills.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/spaces.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/spaces.cpython-310.pyc deleted file mode 100644 index e7f19657053477f05b1ee08e0016dcaa432addae..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/spaces.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/system.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/system.cpython-310.pyc deleted file mode 100644 index 4ca1a884f7036e64cdec16ab7e29ae8e78f0a63c..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/system.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/upload.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/upload.cpython-310.pyc deleted file mode 100644 index 539b364f2003374e88afd702e677a8bb060de5a0..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/upload.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/upload_large_folder.cpython-310.pyc b/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/upload_large_folder.cpython-310.pyc deleted file mode 100644 index 9487776fa11c64b1e0857b1940950f0fe661b11a..0000000000000000000000000000000000000000 Binary files a/venv/lib/python3.10/site-packages/huggingface_hub/cli/__pycache__/upload_large_folder.cpython-310.pyc and /dev/null differ diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/_cli_utils.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/_cli_utils.py deleted file mode 100644 index f0f8608739ad009f8327de362ab7e02a9245bb79..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/_cli_utils.py +++ /dev/null @@ -1,513 +0,0 @@ -# Copyright 2022 The HuggingFace Team. All rights reserved. -# -# 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. -"""Contains CLI utilities (styling, helpers).""" - -import dataclasses -import datetime -import importlib.metadata -import json -import os -import re -import time -from enum import Enum -from pathlib import Path -from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, Optional, Sequence, Union, cast - -import click -import typer - -from huggingface_hub import __version__, constants -from huggingface_hub.utils import ANSI, get_session, hf_raise_for_status, installation_method, logging, tabulate - - -logger = logging.get_logger() - -# Arbitrary maximum length of a cell in a table output -_MAX_CELL_LENGTH = 35 - -if TYPE_CHECKING: - from huggingface_hub.hf_api import HfApi - - -def get_hf_api(token: Optional[str] = None) -> "HfApi": - # Import here to avoid circular import - from huggingface_hub.hf_api import HfApi - - return HfApi(token=token, library_name="huggingface-cli", library_version=__version__) - - -#### TYPER UTILS - -CLI_REFERENCE_URL = "https://huggingface.co/docs/huggingface_hub/en/guides/cli" - - -def generate_epilog(examples: list[str], docs_anchor: Optional[str] = None) -> str: - """Generate an epilog with examples and a Learn More section. - - Args: - examples: List of example commands (without the `$ ` prefix). - docs_anchor: Optional anchor for the docs URL (e.g., "#hf-download"). - - Returns: - Formatted epilog string. - """ - docs_url = f"{CLI_REFERENCE_URL}{docs_anchor}" if docs_anchor else CLI_REFERENCE_URL - examples_str = "\n".join(f" $ {ex}" for ex in examples) - return f"""\ -Examples -{examples_str} - -Learn more - Use `hf --help` for more information about a command. - Read the documentation at {docs_url} -""" - - -TOPIC_T = Union[Literal["main", "help"], str] - - -def _format_epilog_no_indent(epilog: Optional[str], ctx: click.Context, formatter: click.HelpFormatter) -> None: - """Write the epilog without indentation.""" - if epilog: - formatter.write_paragraph() - for line in epilog.split("\n"): - formatter.write_text(line) - - -class HFCliTyperGroup(typer.core.TyperGroup): - """ - Typer Group that: - - lists commands alphabetically within sections. - - separates commands by topic (main, help, etc.). - - formats epilog without extra indentation. - """ - - def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: - topics: dict[str, list] = {} - - for name in self.list_commands(ctx): - cmd = self.get_command(ctx, name) - if cmd is None or cmd.hidden: - continue - help_text = cmd.get_short_help_str(limit=formatter.width) - topic = getattr(cmd, "topic", "main") - topics.setdefault(topic, []).append((name, help_text)) - - with formatter.section("Main commands"): - formatter.write_dl(topics["main"]) - for topic in sorted(topics.keys()): - if topic == "main": - continue - with formatter.section(f"{topic.capitalize()} commands"): - formatter.write_dl(topics[topic]) - - def format_epilog(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: - # Collect examples from all commands - all_examples: list[str] = [] - for name in self.list_commands(ctx): - cmd = self.get_command(ctx, name) - if cmd is None or cmd.hidden: - continue - cmd_examples = getattr(cmd, "examples", []) - all_examples.extend(cmd_examples) - - if all_examples: - epilog = generate_epilog(all_examples) - _format_epilog_no_indent(epilog, ctx, formatter) - elif self.epilog: - _format_epilog_no_indent(self.epilog, ctx, formatter) - - def list_commands(self, ctx: click.Context) -> list[str]: # type: ignore[name-defined] - # click.Group stores both commands and subgroups in `self.commands` - return sorted(self.commands.keys()) - - -def HFCliCommand(topic: TOPIC_T, examples: Optional[list[str]] = None) -> type[typer.core.TyperCommand]: - def format_epilog(self: click.Command, ctx: click.Context, formatter: click.HelpFormatter) -> None: - _format_epilog_no_indent(self.epilog, ctx, formatter) - - return type( - f"TyperCommand{topic.capitalize()}", - (typer.core.TyperCommand,), - {"topic": topic, "examples": examples or [], "format_epilog": format_epilog}, - ) - - -class HFCliApp(typer.Typer): - """Custom Typer app for Hugging Face CLI.""" - - def command( # type: ignore[override] - self, - name: Optional[str] = None, - *, - topic: TOPIC_T = "main", - examples: Optional[list[str]] = None, - context_settings: Optional[dict[str, Any]] = None, - help: Optional[str] = None, - epilog: Optional[str] = None, - short_help: Optional[str] = None, - options_metavar: str = "[OPTIONS]", - add_help_option: bool = True, - no_args_is_help: bool = False, - hidden: bool = False, - deprecated: bool = False, - rich_help_panel: Optional[str] = None, - ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: - # Generate epilog from examples if not explicitly provided - if epilog is None and examples: - epilog = generate_epilog(examples) - - def _inner(func: Callable[..., Any]) -> Callable[..., Any]: - return super(HFCliApp, self).command( - name, - cls=HFCliCommand(topic, examples), - context_settings=context_settings, - help=help, - epilog=epilog, - short_help=short_help, - options_metavar=options_metavar, - add_help_option=add_help_option, - no_args_is_help=no_args_is_help, - hidden=hidden, - deprecated=deprecated, - rich_help_panel=rich_help_panel, - )(func) - - return _inner - - -def typer_factory(help: str, epilog: Optional[str] = None) -> "HFCliApp": - """Create a Typer app with consistent settings. - - Args: - help: Help text for the app. - epilog: Optional epilog text (use `generate_epilog` to create one). - - Returns: - A configured Typer app. - """ - return HFCliApp( - help=help, - epilog=epilog, - add_completion=True, - no_args_is_help=True, - cls=HFCliTyperGroup, - # Disable rich completely for consistent experience - rich_markup_mode=None, - rich_help_panel=None, - pretty_exceptions_enable=False, - # Increase max content width for better readability - context_settings={ - "max_content_width": 120, - }, - ) - - -class RepoType(str, Enum): - model = "model" - dataset = "dataset" - space = "space" - - -RepoIdArg = Annotated[ - str, - typer.Argument( - help="The ID of the repo (e.g. `username/repo-name`).", - ), -] - - -RepoTypeOpt = Annotated[ - RepoType, - typer.Option( - help="The type of repository (model, dataset, or space).", - ), -] - -TokenOpt = Annotated[ - Optional[str], - typer.Option( - help="A User Access Token generated from https://huggingface.co/settings/tokens.", - ), -] - -PrivateOpt = Annotated[ - Optional[bool], - typer.Option( - help="Whether to create a private repo if repo doesn't exist on the Hub. Ignored if the repo already exists.", - ), -] - -RevisionOpt = Annotated[ - Optional[str], - typer.Option( - help="Git revision id which can be a branch name, a tag, or a commit hash.", - ), -] - - -LimitOpt = Annotated[ - int, - typer.Option(help="Limit the number of results."), -] - -AuthorOpt = Annotated[ - Optional[str], - typer.Option(help="Filter by author or organization."), -] - -FilterOpt = Annotated[ - Optional[list[str]], - typer.Option(help="Filter by tags (e.g. 'text-classification'). Can be used multiple times."), -] - -SearchOpt = Annotated[ - Optional[str], - typer.Option(help="Search query."), -] - - -class OutputFormat(str, Enum): - """Output format for CLI list commands.""" - - table = "table" - json = "json" - - -FormatOpt = Annotated[ - OutputFormat, - typer.Option( - help="Output format (table or json).", - ), -] - -QuietOpt = Annotated[ - bool, - typer.Option( - "-q", - "--quiet", - help="Print only IDs (one per line).", - ), -] - - -def _to_header(name: str) -> str: - """Convert a camelCase or PascalCase string to SCREAMING_SNAKE_CASE to be used as table header.""" - s = re.sub(r"([a-z])([A-Z])", r"\1_\2", name) - return s.upper() - - -def _format_value(value: Any) -> str: - """Convert a value to string for terminal display.""" - if not value: - return "" - if isinstance(value, bool): - return "✔" if value else "" - if isinstance(value, datetime.datetime): - return value.strftime("%Y-%m-%d") - if isinstance(value, str) and re.match(r"^\d{4}-\d{2}-\d{2}T", value): - return value[:10] - if isinstance(value, list): - return ", ".join(_format_value(v) for v in value) - elif isinstance(value, dict): - if "name" in value: # Likely to be a user or org => print name - return str(value["name"]) - # TODO: extend if needed - return json.dumps(value) - return str(value) - - -def _format_cell(value: Any, max_len: int = _MAX_CELL_LENGTH) -> str: - """Format a value + truncate it for table display.""" - cell = _format_value(value) - if len(cell) > max_len: - cell = cell[: max_len - 3] + "..." - return cell - - -def print_as_table( - items: Sequence[dict[str, Any]], - headers: list[str], - row_fn: Callable[[dict[str, Any]], list[str]], -) -> None: - """Print items as a formatted table. - - Args: - items: Sequence of dictionaries representing the items to display. - headers: List of column headers. - row_fn: Function that takes an item dict and returns a list of string values for each column. - """ - if not items: - print("No results found.") - return - rows = cast(list[list[Union[str, int]]], [row_fn(item) for item in items]) - print(tabulate(rows, headers=[_to_header(h) for h in headers])) - - -def print_list_output( - items: Sequence[dict[str, Any]], - format: OutputFormat, - quiet: bool, - id_key: str = "id", - headers: Optional[list[str]] = None, - row_fn: Optional[Callable[[dict[str, Any]], list[str]]] = None, -) -> None: - """Print list command output in the specified format. - - Args: - items: Sequence of dictionaries representing the items to display. - format: Output format (table or json). - quiet: If True, print only IDs (one per line). - id_key: Key to use for extracting IDs in quiet mode. - headers: Optional list of column names for headers. If not provided, auto-detected from keys. - row_fn: Optional function to extract row values. If not provided, uses _format_cell on each column. - """ - if quiet: - for item in items: - print(item[id_key]) - return - - if format == OutputFormat.json: - print(json.dumps(list(items), indent=2)) - return - - if headers is None: - all_columns = list(items[0].keys()) if items else [id_key] - headers = [col for col in all_columns if any(_format_cell(item.get(col)) for item in items)] - - if row_fn is None: - - def row_fn(item: dict[str, Any]) -> list[str]: - return [_format_cell(item.get(col)) for col in headers] # type: ignore[union-attr] - - print_as_table(items, headers=headers, row_fn=row_fn) - - -def _serialize_value(v: object) -> object: - """Recursively serialize a value to be JSON-compatible.""" - if isinstance(v, datetime.datetime): - return v.isoformat() - elif isinstance(v, dict): - return {key: _serialize_value(val) for key, val in v.items() if val is not None} - elif isinstance(v, list): - return [_serialize_value(item) for item in v] - return v - - -def api_object_to_dict(info: Any) -> dict[str, Any]: - """Convert repo info dataclasses to json-serializable dicts.""" - return {k: _serialize_value(v) for k, v in dataclasses.asdict(info).items() if v is not None} - - -def make_expand_properties_parser(valid_properties: list[str]): - """Create a callback to parse and validate comma-separated expand properties.""" - - def _parse_expand_properties(value: Optional[str]) -> Optional[list[str]]: - if value is None: - return None - properties = [p.strip() for p in value.split(",")] - for prop in properties: - if prop not in valid_properties: - raise typer.BadParameter( - f"Invalid expand property: '{prop}'. Valid values are: {', '.join(valid_properties)}" - ) - return properties - - return _parse_expand_properties - - -### PyPI VERSION CHECKER - - -def check_cli_update(library: Literal["huggingface_hub", "transformers"]) -> None: - """ - Check whether a newer version of a library is available on PyPI. - - If a newer version is found, notify the user and suggest updating. - If current version is a pre-release (e.g. `1.0.0.rc1`), or a dev version (e.g. `1.0.0.dev1`), no check is performed. - - This function is called at the entry point of the CLI. It only performs the check once every 24 hours, and any error - during the check is caught and logged, to avoid breaking the CLI. - - Args: - library: The library to check for updates. Currently supports "huggingface_hub" and "transformers". - """ - try: - _check_cli_update(library) - except Exception: - # We don't want the CLI to fail on version checks, no matter the reason. - logger.debug("Error while checking for CLI update.", exc_info=True) - - -def _check_cli_update(library: Literal["huggingface_hub", "transformers"]) -> None: - current_version = importlib.metadata.version(library) - - # Skip if current version is a pre-release or dev version - if any(tag in current_version for tag in ["rc", "dev"]): - return - - # Skip if already checked in the last 24 hours - if os.path.exists(constants.CHECK_FOR_UPDATE_DONE_PATH): - mtime = os.path.getmtime(constants.CHECK_FOR_UPDATE_DONE_PATH) - if (time.time() - mtime) < 24 * 3600: - return - - # Touch the file to mark that we did the check now - Path(constants.CHECK_FOR_UPDATE_DONE_PATH).parent.mkdir(parents=True, exist_ok=True) - Path(constants.CHECK_FOR_UPDATE_DONE_PATH).touch() - - # Check latest version from PyPI - response = get_session().get(f"https://pypi.org/pypi/{library}/json", timeout=2) - hf_raise_for_status(response) - data = response.json() - latest_version = data["info"]["version"] - - # If latest version is different from current, notify user - if current_version != latest_version: - if library == "huggingface_hub": - update_command = _get_huggingface_hub_update_command() - else: - update_command = _get_transformers_update_command() - - click.echo( - ANSI.yellow( - f"A new version of {library} ({latest_version}) is available! " - f"You are using version {current_version}.\n" - f"To update, run: {ANSI.bold(update_command)}\n", - ) - ) - - -def _get_huggingface_hub_update_command() -> str: - """Return the command to update huggingface_hub.""" - method = installation_method() - if method == "brew": - return "brew upgrade huggingface-cli" - elif method == "hf_installer" and os.name == "nt": - return 'powershell -NoProfile -Command "iwr -useb https://hf.co/cli/install.ps1 | iex"' - elif method == "hf_installer": - return "curl -LsSf https://hf.co/cli/install.sh | bash -" - else: # unknown => likely pip - return "pip install -U huggingface_hub" - - -def _get_transformers_update_command() -> str: - """Return the command to update transformers.""" - method = installation_method() - if method == "hf_installer" and os.name == "nt": - return 'powershell -NoProfile -Command "iwr -useb https://hf.co/cli/install.ps1 | iex" -WithTransformers' - elif method == "hf_installer": - return "curl -LsSf https://hf.co/cli/install.sh | bash -s -- --with-transformers" - else: # brew/unknown => likely pip - return "pip install -U transformers" diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/_errors.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/_errors.py deleted file mode 100644 index 611a2fe90db9d078eb6623ca56a2caa0ccd96925..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/_errors.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2026 The HuggingFace Team. All rights reserved. -# -# 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. -"""CLI error handling utilities.""" - -from typing import Callable, Optional - -from huggingface_hub.errors import ( - GatedRepoError, - HfHubHTTPError, - LocalTokenNotFoundError, - RemoteEntryNotFoundError, - RepositoryNotFoundError, - RevisionNotFoundError, -) - - -CLI_ERROR_MAPPINGS: dict[type[Exception], Callable[[Exception], str]] = { - RepositoryNotFoundError: lambda e: ( - "Repository not found. Check the `repo_id` and `repo_type` parameters. If the repo is private, make sure you are authenticated." - ), - RevisionNotFoundError: lambda e: "Revision not found. Check the `revision` parameter.", - GatedRepoError: lambda e: "Access denied. This repository requires approval.", - LocalTokenNotFoundError: lambda e: "Not logged in. Run 'hf auth login' first.", - RemoteEntryNotFoundError: lambda e: "File not found in repository.", - HfHubHTTPError: lambda e: str(e), -} - - -def format_known_exception(e: Exception) -> Optional[str]: - for exc_type, formatter in CLI_ERROR_MAPPINGS.items(): - if isinstance(e, exc_type): - return formatter(e) - return None diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/auth.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/auth.py deleted file mode 100644 index 9cf595db389dbc0d6b5f6ad9c7c3837c805ddcc0..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/auth.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# 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. -"""Contains commands to authenticate to the Hugging Face Hub and interact with your repositories. - -Usage: - # login and save token locally. - hf auth login --token=hf_*** --add-to-git-credential - - # switch between tokens - hf auth switch - - # list all tokens - hf auth list - - # logout from all tokens - hf auth logout - - # check which account you are logged in as - hf auth whoami -""" - -from typing import Annotated, Optional - -import typer - -from huggingface_hub.constants import ENDPOINT -from huggingface_hub.hf_api import whoami - -from .._login import auth_list, auth_switch, login, logout -from ..utils import ANSI, get_stored_tokens, get_token, logging -from ._cli_utils import TokenOpt, typer_factory - - -logger = logging.get_logger(__name__) - - -auth_cli = typer_factory(help="Manage authentication (login, logout, etc.).") - - -@auth_cli.command( - "login", - examples=[ - "hf auth login", - "hf auth login --token $HF_TOKEN", - "hf auth login --token $HF_TOKEN --add-to-git-credential", - ], -) -def auth_login( - token: TokenOpt = None, - add_to_git_credential: Annotated[ - bool, - typer.Option( - help="Save to git credential helper. Useful only if you plan to run git commands directly.", - ), - ] = False, -) -> None: - """Login using a token from huggingface.co/settings/tokens.""" - login(token=token, add_to_git_credential=add_to_git_credential) - - -@auth_cli.command( - "logout", - examples=["hf auth logout", "hf auth logout --token-name my-token"], -) -def auth_logout( - token_name: Annotated[ - Optional[str], - typer.Option(help="Name of token to logout"), - ] = None, -) -> None: - """Logout from a specific token.""" - logout(token_name=token_name) - - -def _select_token_name() -> Optional[str]: - token_names = list(get_stored_tokens().keys()) - - if not token_names: - logger.error("No stored tokens found. Please login first.") - return None - - print("Available stored tokens:") - for i, token_name in enumerate(token_names, 1): - print(f"{i}. {token_name}") - while True: - try: - choice = input("Enter the number of the token to switch to (or 'q' to quit): ") - if choice.lower() == "q": - return None - index = int(choice) - 1 - if 0 <= index < len(token_names): - return token_names[index] - else: - print("Invalid selection. Please try again.") - except ValueError: - print("Invalid input. Please enter a number or 'q' to quit.") - - -@auth_cli.command( - "switch", - examples=["hf auth switch", "hf auth switch --token-name my-token"], -) -def auth_switch_cmd( - token_name: Annotated[ - Optional[str], - typer.Option( - help="Name of the token to switch to", - ), - ] = None, - add_to_git_credential: Annotated[ - bool, - typer.Option( - help="Save to git credential helper. Useful only if you plan to run git commands directly.", - ), - ] = False, -) -> None: - """Switch between access tokens.""" - if token_name is None: - token_name = _select_token_name() - if token_name is None: - print("No token name provided. Aborting.") - raise typer.Exit() - auth_switch(token_name, add_to_git_credential=add_to_git_credential) - - -@auth_cli.command("list", examples=["hf auth list"]) -def auth_list_cmd() -> None: - """List all stored access tokens.""" - auth_list() - - -@auth_cli.command("whoami", examples=["hf auth whoami"]) -def auth_whoami() -> None: - """Find out which huggingface.co account you are logged in as.""" - token = get_token() - if token is None: - print("Not logged in") - raise typer.Exit() - info = whoami(token) - print(ANSI.bold("user: "), info["name"]) - orgs = [org["name"] for org in info["orgs"]] - if orgs: - print(ANSI.bold("orgs: "), ",".join(orgs)) - - if ENDPOINT != "https://huggingface.co": - print(f"Authenticated through private endpoint: {ENDPOINT}") diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/cache.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/cache.py deleted file mode 100644 index 0aae9bab187840822a18fc41c6da6ece19c1bab2..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/cache.py +++ /dev/null @@ -1,811 +0,0 @@ -# coding=utf-8 -# Copyright 2025-present, the HuggingFace Inc. team. -# -# 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. -"""Contains the 'hf cache' command group with cache management subcommands.""" - -import json -import re -import sys -import time -from collections import defaultdict -from dataclasses import dataclass -from enum import Enum -from typing import Annotated, Any, Callable, Dict, List, Mapping, Optional, Tuple - -import typer - -from huggingface_hub.errors import CLIError - -from ..utils import ( - ANSI, - CachedRepoInfo, - CachedRevisionInfo, - CacheNotFound, - HFCacheInfo, - _format_size, - scan_cache_dir, - tabulate, -) -from ..utils._parsing import parse_duration, parse_size -from ._cli_utils import ( - OutputFormat, - RepoIdArg, - RepoTypeOpt, - RevisionOpt, - TokenOpt, - get_hf_api, - typer_factory, -) - - -cache_cli = typer_factory(help="Manage local cache directory.") - - -#### Cache helper utilities - - -@dataclass(frozen=True) -class _DeletionResolution: - revisions: frozenset[str] - selected: dict[CachedRepoInfo, frozenset[CachedRevisionInfo]] - missing: tuple[str, ...] - - -_FILTER_PATTERN = re.compile(r"^(?P[a-zA-Z_]+)\s*(?P==|!=|>=|<=|>|<|=)\s*(?P.+)$") -_ALLOWED_OPERATORS = {"=", "!=", ">", "<", ">=", "<="} -_FILTER_KEYS = {"accessed", "modified", "refs", "size", "type"} -_SORT_KEYS = {"accessed", "modified", "name", "size"} -_SORT_PATTERN = re.compile(r"^(?P[a-zA-Z_]+)(?::(?Pasc|desc))?$") -_SORT_DEFAULT_ORDER = { - # Default ordering: accessed/modified/size are descending (newest/biggest first), name is ascending - "accessed": "desc", - "modified": "desc", - "size": "desc", - "name": "asc", -} - - -# Dynamically generate SortOptions enum from _SORT_KEYS -_sort_options_dict = {} -for key in sorted(_SORT_KEYS): - _sort_options_dict[key] = key - _sort_options_dict[f"{key}_asc"] = f"{key}:asc" - _sort_options_dict[f"{key}_desc"] = f"{key}:desc" - -SortOptions = Enum("SortOptions", _sort_options_dict, type=str, module=__name__) # type: ignore - - -@dataclass(frozen=True) -class CacheDeletionCounts: - """Simple counters summarizing cache deletions for CLI messaging.""" - - repo_count: int - partial_revision_count: int - total_revision_count: int - - -CacheEntry = Tuple[CachedRepoInfo, Optional[CachedRevisionInfo]] -RepoRefsMap = Dict[CachedRepoInfo, frozenset[str]] - - -def summarize_deletions( - selected_by_repo: Mapping[CachedRepoInfo, frozenset[CachedRevisionInfo]], -) -> CacheDeletionCounts: - """Summarize deletions across repositories.""" - repo_count = 0 - total_revisions = 0 - revisions_in_full_repos = 0 - - for repo, revisions in selected_by_repo.items(): - total_revisions += len(revisions) - if len(revisions) == len(repo.revisions): - repo_count += 1 - revisions_in_full_repos += len(revisions) - - partial_revision_count = total_revisions - revisions_in_full_repos - return CacheDeletionCounts(repo_count, partial_revision_count, total_revisions) - - -def print_cache_selected_revisions(selected_by_repo: Mapping[CachedRepoInfo, frozenset[CachedRevisionInfo]]) -> None: - """Pretty-print selected cache revisions during confirmation prompts.""" - for repo in sorted(selected_by_repo.keys(), key=lambda repo: (repo.repo_type, repo.repo_id.lower())): - repo_key = f"{repo.repo_type}/{repo.repo_id}" - revisions = sorted(selected_by_repo[repo], key=lambda rev: rev.commit_hash) - if len(revisions) == len(repo.revisions): - print(f" - {repo_key} (entire repo)") - continue - - print(f" - {repo_key}:") - for revision in revisions: - refs = " ".join(sorted(revision.refs)) or "(detached)" - print(f" {revision.commit_hash} [{refs}] {revision.size_on_disk_str}") - - -def build_cache_index( - hf_cache_info: HFCacheInfo, -) -> Tuple[ - Dict[str, CachedRepoInfo], - Dict[str, Tuple[CachedRepoInfo, CachedRevisionInfo]], -]: - """Create lookup tables so CLI commands can resolve repo ids and revisions quickly.""" - repo_lookup: dict[str, CachedRepoInfo] = {} - revision_lookup: dict[str, tuple[CachedRepoInfo, CachedRevisionInfo]] = {} - for repo in hf_cache_info.repos: - repo_key = repo.cache_id.lower() - repo_lookup[repo_key] = repo - for revision in repo.revisions: - revision_lookup[revision.commit_hash.lower()] = (repo, revision) - return repo_lookup, revision_lookup - - -def collect_cache_entries( - hf_cache_info: HFCacheInfo, *, include_revisions: bool -) -> Tuple[List[CacheEntry], RepoRefsMap]: - """Flatten cache metadata into rows consumed by `hf cache ls`.""" - entries: List[CacheEntry] = [] - repo_refs_map: RepoRefsMap = {} - sorted_repos = sorted(hf_cache_info.repos, key=lambda repo: (repo.repo_type, repo.repo_id.lower())) - for repo in sorted_repos: - repo_refs_map[repo] = frozenset({ref for revision in repo.revisions for ref in revision.refs}) - if include_revisions: - for revision in sorted(repo.revisions, key=lambda rev: rev.commit_hash): - entries.append((repo, revision)) - else: - entries.append((repo, None)) - if include_revisions: - entries.sort( - key=lambda entry: ( - entry[0].cache_id, - entry[1].commit_hash if entry[1] is not None else "", - ) - ) - else: - entries.sort(key=lambda entry: entry[0].cache_id) - return entries, repo_refs_map - - -def compile_cache_filter( - expr: str, repo_refs_map: RepoRefsMap -) -> Callable[[CachedRepoInfo, Optional[CachedRevisionInfo], float], bool]: - """Convert a `hf cache ls` filter expression into the yes/no test we apply to each cache entry before displaying it.""" - match = _FILTER_PATTERN.match(expr.strip()) - if not match: - raise ValueError(f"Invalid filter expression: '{expr}'.") - - key = match.group("key").lower() - op = match.group("op") - value_raw = match.group("value").strip() - - if op not in _ALLOWED_OPERATORS: - raise ValueError(f"Unsupported operator '{op}' in filter '{expr}'. Must be one of {list(_ALLOWED_OPERATORS)}.") - - if key not in _FILTER_KEYS: - raise ValueError(f"Unsupported filter key '{key}' in '{expr}'. Must be one of {list(_FILTER_KEYS)}.") - # at this point we know that key is in `_FILTER_KEYS` - if key == "size": - size_threshold = parse_size(value_raw) - return lambda repo, revision, _: _compare_numeric( - revision.size_on_disk if revision is not None else repo.size_on_disk, - op, - size_threshold, - ) - - if key in {"modified", "accessed"}: - seconds = parse_duration(value_raw.strip()) - - def _time_filter(repo: CachedRepoInfo, revision: Optional[CachedRevisionInfo], now: float) -> bool: - timestamp = ( - repo.last_accessed - if key == "accessed" - else revision.last_modified - if revision is not None - else repo.last_modified - ) - if timestamp is None: - return False - return _compare_numeric(now - timestamp, op, seconds) - - return _time_filter - - if key == "type": - expected = value_raw.lower() - - if op != "=": - raise ValueError(f"Only '=' is supported for 'type' filters. Got '{op}'.") - - def _type_filter(repo: CachedRepoInfo, revision: Optional[CachedRevisionInfo], _: float) -> bool: - return repo.repo_type.lower() == expected - - return _type_filter - - else: # key == "refs" - if op != "=": - raise ValueError(f"Only '=' is supported for 'refs' filters. Got {op}.") - - def _refs_filter(repo: CachedRepoInfo, revision: Optional[CachedRevisionInfo], _: float) -> bool: - refs = revision.refs if revision is not None else repo_refs_map.get(repo, frozenset()) - return value_raw.lower() in [ref.lower() for ref in refs] - - return _refs_filter - - -def _build_cache_export_payload( - entries: List[CacheEntry], *, include_revisions: bool, repo_refs_map: RepoRefsMap -) -> List[Dict[str, Any]]: - """Normalize cache entries into serializable records for JSON/CSV exports.""" - payload: List[Dict[str, Any]] = [] - for repo, revision in entries: - if include_revisions: - if revision is None: - continue - record: Dict[str, Any] = { - "repo_id": repo.repo_id, - "repo_type": repo.repo_type, - "revision": revision.commit_hash, - "snapshot_path": str(revision.snapshot_path), - "size_on_disk": revision.size_on_disk, - "last_accessed": repo.last_accessed, - "last_modified": revision.last_modified, - "refs": sorted(revision.refs), - } - else: - record = { - "repo_id": repo.repo_id, - "repo_type": repo.repo_type, - "size_on_disk": repo.size_on_disk, - "last_accessed": repo.last_accessed, - "last_modified": repo.last_modified, - "refs": sorted(repo_refs_map.get(repo, frozenset())), - } - payload.append(record) - return payload - - -def print_cache_entries_table( - entries: List[CacheEntry], *, include_revisions: bool, repo_refs_map: RepoRefsMap -) -> None: - """Render cache entries as a table and show a human-readable summary.""" - if not entries: - message = "No cached revisions found." if include_revisions else "No cached repositories found." - print(message) - return - table_rows: List[List[str]] - if include_revisions: - headers = ["ID", "REVISION", "SIZE", "LAST_MODIFIED", "REFS"] - table_rows = [ - [ - repo.cache_id, - revision.commit_hash, - revision.size_on_disk_str.rjust(8), - revision.last_modified_str, - " ".join(sorted(revision.refs)), - ] - for repo, revision in entries - if revision is not None - ] - else: - headers = ["ID", "SIZE", "LAST_ACCESSED", "LAST_MODIFIED", "REFS"] - table_rows = [ - [ - repo.cache_id, - repo.size_on_disk_str.rjust(8), - repo.last_accessed_str or "", - repo.last_modified_str, - " ".join(sorted(repo_refs_map.get(repo, frozenset()))), - ] - for repo, _ in entries - ] - - print(tabulate(table_rows, headers=headers)) # type: ignore[arg-type] - - unique_repos = {repo for repo, _ in entries} - repo_count = len(unique_repos) - if include_revisions: - revision_count = sum(1 for _, revision in entries if revision is not None) - total_size = sum(revision.size_on_disk for _, revision in entries if revision is not None) - else: - revision_count = sum(len(repo.revisions) for repo in unique_repos) - total_size = sum(repo.size_on_disk for repo in unique_repos) - - summary = f"\nFound {repo_count} repo(s) for a total of {revision_count} revision(s) and {_format_size(total_size)} on disk." - print(ANSI.bold(summary)) - - -def print_cache_entries_json( - entries: List[CacheEntry], *, include_revisions: bool, repo_refs_map: RepoRefsMap -) -> None: - """Dump cache entries as JSON for scripting or automation.""" - payload = _build_cache_export_payload(entries, include_revisions=include_revisions, repo_refs_map=repo_refs_map) - json.dump(payload, sys.stdout, indent=2) - sys.stdout.write("\n") - - -def _compare_numeric(left: Optional[float], op: str, right: float) -> bool: - """Evaluate numeric comparisons for filters.""" - if left is None: - return False - - comparisons = { - "=": left == right, - "!=": left != right, - ">": left > right, - "<": left < right, - ">=": left >= right, - "<=": left <= right, - } - - if op not in comparisons: - raise ValueError(f"Unsupported numeric comparison operator: {op}") - - return comparisons[op] - - -def compile_cache_sort(sort_expr: str) -> tuple[Callable[[CacheEntry], tuple[Any, ...]], bool]: - """Convert a `hf cache ls` sort expression into a key function for sorting entries. - - Returns: - A tuple of (key_function, reverse_flag) where reverse_flag indicates whether - to sort in descending order (True) or ascending order (False). - """ - match = _SORT_PATTERN.match(sort_expr.strip().lower()) - if not match: - raise ValueError(f"Invalid sort expression: '{sort_expr}'. Expected format: 'key' or 'key:asc' or 'key:desc'.") - - key = match.group("key").lower() - explicit_order = match.group("order") - - if key not in _SORT_KEYS: - raise ValueError(f"Unsupported sort key '{key}' in '{sort_expr}'. Must be one of {list(_SORT_KEYS)}.") - - # Use explicit order if provided, otherwise use default for the key - order = explicit_order if explicit_order else _SORT_DEFAULT_ORDER[key] - reverse = order == "desc" - - def _sort_key(entry: CacheEntry) -> tuple[Any, ...]: - repo, revision = entry - - if key == "name": - # Sort by cache_id (repo type/id) - value: Any = repo.cache_id.lower() - return (value,) - - if key == "size": - # Use revision size if available, otherwise repo size - value = revision.size_on_disk if revision is not None else repo.size_on_disk - return (value,) - - if key == "accessed": - # For revisions, accessed is not available per-revision, use repo's last_accessed - # For repos, use repo's last_accessed - value = repo.last_accessed if repo.last_accessed is not None else 0.0 - return (value,) - - if key == "modified": - # Use revision's last_modified if available, otherwise repo's last_modified - if revision is not None: - value = revision.last_modified if revision.last_modified is not None else 0.0 - else: - value = repo.last_modified if repo.last_modified is not None else 0.0 - return (value,) - - # Should never reach here due to validation above - raise ValueError(f"Unsupported sort key: {key}") - - return _sort_key, reverse - - -def _resolve_deletion_targets(hf_cache_info: HFCacheInfo, targets: list[str]) -> _DeletionResolution: - """Resolve the deletion targets into a deletion resolution.""" - repo_lookup, revision_lookup = build_cache_index(hf_cache_info) - - selected: dict[CachedRepoInfo, set[CachedRevisionInfo]] = defaultdict(set) - revisions: set[str] = set() - missing: list[str] = [] - - for raw_target in targets: - target = raw_target.strip() - if not target: - continue - lowered = target.lower() - - if re.fullmatch(r"[0-9a-fA-F]{40}", lowered): - match = revision_lookup.get(lowered) - if match is None: - missing.append(raw_target) - continue - repo, revision = match - selected[repo].add(revision) - revisions.add(revision.commit_hash) - continue - - matched_repo = repo_lookup.get(lowered) - if matched_repo is None: - missing.append(raw_target) - continue - - for revision in matched_repo.revisions: - selected[matched_repo].add(revision) - revisions.add(revision.commit_hash) - - frozen_selected = {repo: frozenset(revs) for repo, revs in selected.items()} - return _DeletionResolution( - revisions=frozenset(revisions), - selected=frozen_selected, - missing=tuple(missing), - ) - - -#### Cache CLI commands - - -@cache_cli.command( - examples=[ - "hf cache ls", - "hf cache ls --revisions", - 'hf cache ls --filter "size>1GB" --limit 20', - "hf cache ls --format json", - ], -) -def ls( - cache_dir: Annotated[ - Optional[str], - typer.Option( - help="Cache directory to scan (defaults to Hugging Face cache).", - ), - ] = None, - revisions: Annotated[ - bool, - typer.Option( - help="Include revisions in the output instead of aggregated repositories.", - ), - ] = False, - filter: Annotated[ - Optional[list[str]], - typer.Option( - "-f", - "--filter", - help="Filter entries (e.g. 'size>1GB', 'type=model', 'accessed>7d'). Can be used multiple times.", - ), - ] = None, - format: Annotated[ - OutputFormat, - typer.Option( - help="Output format.", - ), - ] = OutputFormat.table, - quiet: Annotated[ - bool, - typer.Option( - "-q", - "--quiet", - help="Print only IDs (repo IDs or revision hashes).", - ), - ] = False, - sort: Annotated[ - Optional[SortOptions], - typer.Option( - help="Sort entries by key. Supported keys: 'accessed', 'modified', 'name', 'size'. " - "Append ':asc' or ':desc' to explicitly set the order (e.g., 'modified:asc'). " - "Defaults: 'accessed', 'modified', 'size' default to 'desc' (newest/biggest first); " - "'name' defaults to 'asc' (alphabetical).", - ), - ] = None, - limit: Annotated[ - Optional[int], - typer.Option( - help="Limit the number of results returned. Returns only the top N entries after sorting.", - ), - ] = None, -) -> None: - """List cached repositories or revisions.""" - try: - hf_cache_info = scan_cache_dir(cache_dir) - except CacheNotFound as exc: - raise CLIError(f"Cache directory not found: {exc.cache_dir}") from exc - - filters = filter or [] - - entries, repo_refs_map = collect_cache_entries(hf_cache_info, include_revisions=revisions) - try: - filter_fns = [compile_cache_filter(expr, repo_refs_map) for expr in filters] - except ValueError as exc: - raise typer.BadParameter(str(exc)) from exc - - now = time.time() - for fn in filter_fns: - entries = [entry for entry in entries if fn(entry[0], entry[1], now)] - - # Apply sorting if requested - if sort: - try: - sort_key_fn, reverse = compile_cache_sort(sort.value) - entries.sort(key=sort_key_fn, reverse=reverse) - except ValueError as exc: - raise typer.BadParameter(str(exc)) from exc - - # Apply limit if requested - if limit is not None: - if limit < 0: - raise typer.BadParameter(f"Limit must be a positive integer, got {limit}.") - entries = entries[:limit] - - if quiet: - for repo, revision in entries: - print(revision.commit_hash if revision is not None else repo.cache_id) - return - - formatters = { - OutputFormat.table: print_cache_entries_table, - OutputFormat.json: print_cache_entries_json, - } - return formatters[format](entries, include_revisions=revisions, repo_refs_map=repo_refs_map) - - -@cache_cli.command( - examples=[ - "hf cache rm model/gpt2", - "hf cache rm ", - "hf cache rm model/gpt2 --dry-run", - "hf cache rm model/gpt2 --yes", - ], -) -def rm( - targets: Annotated[ - list[str], - typer.Argument( - help="One or more repo IDs (e.g. model/bert-base-uncased) or revision hashes to delete.", - ), - ], - cache_dir: Annotated[ - Optional[str], - typer.Option( - help="Cache directory to scan (defaults to Hugging Face cache).", - ), - ] = None, - yes: Annotated[ - bool, - typer.Option( - "-y", - "--yes", - help="Skip confirmation prompt.", - ), - ] = False, - dry_run: Annotated[ - bool, - typer.Option( - help="Preview deletions without removing anything.", - ), - ] = False, -) -> None: - """Remove cached repositories or revisions.""" - try: - hf_cache_info = scan_cache_dir(cache_dir) - except CacheNotFound as exc: - raise CLIError(f"Cache directory not found: {exc.cache_dir}") from exc - - resolution = _resolve_deletion_targets(hf_cache_info, targets) - - if resolution.missing: - print("Could not find the following targets in the cache:") - for entry in resolution.missing: - print(f" - {entry}") - - if len(resolution.revisions) == 0: - print("Nothing to delete.") - raise typer.Exit(code=0) - - strategy = hf_cache_info.delete_revisions(*sorted(resolution.revisions)) - counts = summarize_deletions(resolution.selected) - - summary_parts: list[str] = [] - if counts.repo_count: - summary_parts.append(f"{counts.repo_count} repo(s)") - if counts.partial_revision_count: - summary_parts.append(f"{counts.partial_revision_count} revision(s)") - if not summary_parts: - summary_parts.append(f"{counts.total_revision_count} revision(s)") - - summary_text = " and ".join(summary_parts) - print(f"About to delete {summary_text} totalling {strategy.expected_freed_size_str}.") - print_cache_selected_revisions(resolution.selected) - - if dry_run: - print("Dry run: no files were deleted.") - return - - if not yes and not typer.confirm("Proceed with deletion?", default=False): - print("Deletion cancelled.") - return - - strategy.execute() - counts = summarize_deletions(resolution.selected) - print( - f"Deleted {counts.repo_count} repo(s) and {counts.total_revision_count} revision(s); freed {strategy.expected_freed_size_str}." - ) - - -@cache_cli.command(examples=["hf cache prune", "hf cache prune --dry-run"]) -def prune( - cache_dir: Annotated[ - Optional[str], - typer.Option( - help="Cache directory to scan (defaults to Hugging Face cache).", - ), - ] = None, - yes: Annotated[ - bool, - typer.Option( - "-y", - "--yes", - help="Skip confirmation prompt.", - ), - ] = False, - dry_run: Annotated[ - bool, - typer.Option( - help="Preview deletions without removing anything.", - ), - ] = False, -) -> None: - """Remove detached revisions from the cache.""" - try: - hf_cache_info = scan_cache_dir(cache_dir) - except CacheNotFound as exc: - raise CLIError(f"Cache directory not found: {exc.cache_dir}") from exc - - selected: dict[CachedRepoInfo, frozenset[CachedRevisionInfo]] = {} - revisions: set[str] = set() - for repo in hf_cache_info.repos: - detached = frozenset(revision for revision in repo.revisions if len(revision.refs) == 0) - if not detached: - continue - selected[repo] = detached - revisions.update(revision.commit_hash for revision in detached) - - if len(revisions) == 0: - print("No unreferenced revisions found. Nothing to prune.") - return - - resolution = _DeletionResolution( - revisions=frozenset(revisions), - selected=selected, - missing=(), - ) - strategy = hf_cache_info.delete_revisions(*sorted(resolution.revisions)) - counts = summarize_deletions(selected) - - print( - f"About to delete {counts.total_revision_count} unreferenced revision(s) ({strategy.expected_freed_size_str} total)." - ) - print_cache_selected_revisions(selected) - - if dry_run: - print("Dry run: no files were deleted.") - return - - if not yes and not typer.confirm("Proceed?"): - print("Pruning cancelled.") - return - - strategy.execute() - print(f"Deleted {counts.total_revision_count} unreferenced revision(s); freed {strategy.expected_freed_size_str}.") - - -@cache_cli.command( - examples=[ - "hf cache verify gpt2", - "hf cache verify gpt2 --revision refs/pr/1", - "hf cache verify my-dataset --repo-type dataset", - ], -) -def verify( - repo_id: RepoIdArg, - repo_type: RepoTypeOpt = RepoTypeOpt.model, - revision: RevisionOpt = None, - cache_dir: Annotated[ - Optional[str], - typer.Option( - help="Cache directory to use when verifying files from cache (defaults to Hugging Face cache).", - ), - ] = None, - local_dir: Annotated[ - Optional[str], - typer.Option( - help="If set, verify files under this directory instead of the cache.", - ), - ] = None, - fail_on_missing_files: Annotated[ - bool, - typer.Option( - "--fail-on-missing-files", - help="Fail if some files exist on the remote but are missing locally.", - ), - ] = False, - fail_on_extra_files: Annotated[ - bool, - typer.Option( - "--fail-on-extra-files", - help="Fail if some files exist locally but are not present on the remote revision.", - ), - ] = False, - token: TokenOpt = None, -) -> None: - """Verify checksums for a single repo revision from cache or a local directory. - - Examples: - - Verify main revision in cache: `hf cache verify gpt2` - - Verify specific revision: `hf cache verify gpt2 --revision refs/pr/1` - - Verify dataset: `hf cache verify karpathy/fineweb-edu-100b-shuffle --repo-type dataset` - - Verify local dir: `hf cache verify deepseek-ai/DeepSeek-OCR --local-dir /path/to/repo` - """ - - if local_dir is not None and cache_dir is not None: - print("Cannot pass both --local-dir and --cache-dir. Use one or the other.") - raise typer.Exit(code=2) - - api = get_hf_api(token=token) - - result = api.verify_repo_checksums( - repo_id=repo_id, - repo_type=repo_type.value if hasattr(repo_type, "value") else str(repo_type), - revision=revision, - local_dir=local_dir, - cache_dir=cache_dir, - token=token, - ) - - exit_code = 0 - - has_mismatches = bool(result.mismatches) - if has_mismatches: - print("❌ Checksum verification failed for the following file(s):") - for m in result.mismatches: - print(f" - {m['path']}: expected {m['expected']} ({m['algorithm']}), got {m['actual']}") - exit_code = 1 - - if result.missing_paths: - if fail_on_missing_files: - print("Missing files (present remotely, absent locally):") - for p in result.missing_paths: - print(f" - {p}") - exit_code = 1 - else: - warning = ( - f"{len(result.missing_paths)} remote file(s) are missing locally. " - "Use --fail-on-missing-files for details." - ) - print(f"⚠️ {warning}") - - if result.extra_paths: - if fail_on_extra_files: - print("Extra files (present locally, absent remotely):") - for p in result.extra_paths: - print(f" - {p}") - exit_code = 1 - else: - warning = ( - f"{len(result.extra_paths)} local file(s) do not exist on the remote repo. " - "Use --fail-on-extra-files for details." - ) - print(f"⚠️ {warning}") - - verified_location = result.verified_path - - if exit_code != 0: - print(f"❌ Verification failed for '{repo_id}' ({repo_type.value}) in {verified_location}.") - print(f" Revision: {result.revision}") - raise typer.Exit(code=exit_code) - - print(f"✅ Verified {result.checked_count} file(s) for '{repo_id}' ({repo_type.value}) in {verified_location}") - print(" All checksums match.") diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/collections.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/collections.py deleted file mode 100644 index 9f6f66fd968cd12a861810183a7c8affc23f5246..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/collections.py +++ /dev/null @@ -1,331 +0,0 @@ -# Copyright 2026 The HuggingFace Team. All rights reserved. -# -# 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. -"""Contains commands to interact with collections on the Hugging Face Hub. - -Usage: - # list collections on the Hub - hf collections ls - - # list collections for a specific user - hf collections ls --owner username - - # get info about a collection - hf collections info username/collection-slug - - # create a new collection - hf collections create "My Collection" --description "A collection of models" - - # add an item to a collection - hf collections add-item username/collection-slug username/model-name model - - # delete a collection - hf collections delete username/collection-slug -""" - -import enum -import json -from typing import Annotated, Optional, get_args - -import typer - -from huggingface_hub.hf_api import CollectionItemType_T, CollectionSort_T - -from ._cli_utils import ( - FormatOpt, - LimitOpt, - OutputFormat, - QuietOpt, - TokenOpt, - api_object_to_dict, - get_hf_api, - print_list_output, - typer_factory, -) - - -# Build enums dynamically from Literal types to avoid duplication -_COLLECTION_ITEM_TYPES = get_args(CollectionItemType_T) -CollectionItemType = enum.Enum("CollectionItemType", {t: t for t in _COLLECTION_ITEM_TYPES}, type=str) # type: ignore[misc] - -_COLLECTION_SORT_OPTIONS = get_args(CollectionSort_T) -CollectionSort = enum.Enum("CollectionSort", {s: s for s in _COLLECTION_SORT_OPTIONS}, type=str) # type: ignore[misc] - - -collections_cli = typer_factory(help="Interact with collections on the Hub.") - - -@collections_cli.command( - "ls", - examples=[ - "hf collections ls", - "hf collections ls --owner nvidia", - "hf collections ls --item models/teknium/OpenHermes-2.5-Mistral-7B --limit 10", - ], -) -def collections_ls( - owner: Annotated[ - Optional[str], - typer.Option(help="Filter by owner username or organization."), - ] = None, - item: Annotated[ - Optional[str], - typer.Option( - help='Filter collections containing a specific item (e.g., "models/gpt2", "datasets/squad", "papers/2311.12983").' - ), - ] = None, - sort: Annotated[ - Optional[CollectionSort], - typer.Option(help="Sort results by last modified, trending, or upvotes."), - ] = None, - limit: LimitOpt = 10, - format: FormatOpt = OutputFormat.table, - quiet: QuietOpt = False, - token: TokenOpt = None, -) -> None: - """List collections on the Hub.""" - api = get_hf_api(token=token) - sort_key = sort.value if sort else None - results = [ - api_object_to_dict(collection) - for collection in api.list_collections( - owner=owner, - item=item, - sort=sort_key, # type: ignore[arg-type] - limit=limit, - ) - ] - print_list_output(results, format=format, quiet=quiet) - - -@collections_cli.command( - "info", - examples=[ - "hf collections info username/my-collection-slug", - ], -) -def collections_info( - collection_slug: Annotated[str, typer.Argument(help="The collection slug (e.g., 'username/collection-slug').")], - token: TokenOpt = None, -) -> None: - """Get info about a collection on the Hub.""" - api = get_hf_api(token=token) - collection = api.get_collection(collection_slug) - print(json.dumps(api_object_to_dict(collection), indent=2)) - - -@collections_cli.command( - "create", - examples=[ - 'hf collections create "My Models"', - 'hf collections create "My Models" --description "A collection of my favorite models" --private', - 'hf collections create "Org Collection" --namespace my-org', - ], -) -def collections_create( - title: Annotated[str, typer.Argument(help="The title of the collection.")], - namespace: Annotated[ - Optional[str], - typer.Option(help="The namespace (username or organization). Defaults to the authenticated user."), - ] = None, - description: Annotated[ - Optional[str], - typer.Option(help="A description for the collection."), - ] = None, - private: Annotated[ - bool, - typer.Option(help="Create a private collection."), - ] = False, - exists_ok: Annotated[ - bool, - typer.Option(help="Do not raise an error if the collection already exists."), - ] = False, - token: TokenOpt = None, -) -> None: - """Create a new collection on the Hub.""" - api = get_hf_api(token=token) - collection = api.create_collection( - title=title, - namespace=namespace, - description=description, - private=private, - exists_ok=exists_ok, - ) - print(f"Collection created: {collection.url}") - print(json.dumps(api_object_to_dict(collection), indent=2)) - - -@collections_cli.command( - "update", - examples=[ - 'hf collections update username/my-collection --title "New Title"', - 'hf collections update username/my-collection --description "Updated description"', - "hf collections update username/my-collection --private --theme green", - ], -) -def collections_update( - collection_slug: Annotated[str, typer.Argument(help="The collection slug (e.g., 'username/collection-slug').")], - title: Annotated[ - Optional[str], - typer.Option(help="The new title for the collection."), - ] = None, - description: Annotated[ - Optional[str], - typer.Option(help="The new description for the collection."), - ] = None, - position: Annotated[ - Optional[int], - typer.Option(help="The new position of the collection in the owner's list."), - ] = None, - private: Annotated[ - Optional[bool], - typer.Option(help="Whether the collection should be private."), - ] = None, - theme: Annotated[ - Optional[str], - typer.Option(help="The theme color for the collection (e.g., 'green', 'blue')."), - ] = None, - token: TokenOpt = None, -) -> None: - """Update a collection's metadata on the Hub.""" - api = get_hf_api(token=token) - collection = api.update_collection_metadata( - collection_slug=collection_slug, - title=title, - description=description, - position=position, - private=private, - theme=theme, - ) - print(f"Collection updated: {collection.url}") - print(json.dumps(api_object_to_dict(collection), indent=2)) - - -@collections_cli.command( - "delete", - examples=[ - "hf collections delete username/my-collection", - "hf collections delete username/my-collection --missing-ok", - ], -) -def collections_delete( - collection_slug: Annotated[str, typer.Argument(help="The collection slug (e.g., 'username/collection-slug').")], - missing_ok: Annotated[ - bool, - typer.Option(help="Do not raise an error if the collection doesn't exist."), - ] = False, - token: TokenOpt = None, -) -> None: - """Delete a collection from the Hub.""" - api = get_hf_api(token=token) - api.delete_collection(collection_slug, missing_ok=missing_ok) - print(f"Collection deleted: {collection_slug}") - - -@collections_cli.command( - "add-item", - examples=[ - "hf collections add-item username/my-collection moonshotai/kimi-k2 model", - 'hf collections add-item username/my-collection Qwen/DeepPlanning dataset --note "Useful dataset"', - "hf collections add-item username/my-collection Tongyi-MAI/Z-Image space", - ], -) -def collections_add_item( - collection_slug: Annotated[str, typer.Argument(help="The collection slug (e.g., 'username/collection-slug').")], - item_id: Annotated[ - str, typer.Argument(help="The ID of the item to add (repo_id for repos, paper ID for papers).") - ], - item_type: Annotated[ - CollectionItemType, - typer.Argument(help="The type of item (model, dataset, space, paper, or collection)."), - ], - note: Annotated[ - Optional[str], - typer.Option(help="A note to attach to the item (max 500 characters)."), - ] = None, - exists_ok: Annotated[ - bool, - typer.Option(help="Do not raise an error if the item is already in the collection."), - ] = False, - token: TokenOpt = None, -) -> None: - """Add an item to a collection.""" - api = get_hf_api(token=token) - collection = api.add_collection_item( - collection_slug=collection_slug, - item_id=item_id, - item_type=item_type.value, # type: ignore[arg-type] - note=note, - exists_ok=exists_ok, - ) - print(f"Item added to collection: {collection_slug}") - print(json.dumps(api_object_to_dict(collection), indent=2)) - - -@collections_cli.command( - "update-item", - examples=[ - 'hf collections update-item username/my-collection ITEM_OBJECT_ID --note "Updated note"', - "hf collections update-item username/my-collection ITEM_OBJECT_ID --position 0", - ], -) -def collections_update_item( - collection_slug: Annotated[str, typer.Argument(help="The collection slug (e.g., 'username/collection-slug').")], - item_object_id: Annotated[ - str, - typer.Argument(help="The ID of the item in the collection (from 'item_object_id' field, not the repo_id)."), - ], - note: Annotated[ - Optional[str], - typer.Option(help="A new note for the item (max 500 characters)."), - ] = None, - position: Annotated[ - Optional[int], - typer.Option(help="The new position of the item in the collection."), - ] = None, - token: TokenOpt = None, -) -> None: - """Update an item in a collection.""" - api = get_hf_api(token=token) - api.update_collection_item( - collection_slug=collection_slug, - item_object_id=item_object_id, - note=note, - position=position, - ) - print(f"Item updated in collection: {collection_slug}") - - -@collections_cli.command("delete-item") -def collections_delete_item( - collection_slug: Annotated[str, typer.Argument(help="The collection slug (e.g., 'username/collection-slug').")], - item_object_id: Annotated[ - str, - typer.Argument( - help="The ID of the item in the collection (retrieved from `item_object_id` field returned by 'hf collections info'." - ), - ], - missing_ok: Annotated[ - bool, - typer.Option(help="Do not raise an error if the item doesn't exist."), - ] = False, - token: TokenOpt = None, -) -> None: - """Delete an item from a collection.""" - api = get_hf_api(token=token) - api.delete_collection_item( - collection_slug=collection_slug, - item_object_id=item_object_id, - missing_ok=missing_ok, - ) - print(f"Item deleted from collection: {collection_slug}") diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/datasets.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/datasets.py deleted file mode 100644 index 3f6d627b80c0c0948c2861d38efb6e4397d9d3d6..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/datasets.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2026 The HuggingFace Team. All rights reserved. -# -# 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. -"""Contains commands to interact with datasets on the Hugging Face Hub. - -Usage: - # list datasets on the Hub - hf datasets ls - - # list datasets with a search query - hf datasets ls --search "code" - - # get info about a dataset - hf datasets info HuggingFaceFW/fineweb -""" - -import enum -import json -from typing import Annotated, Optional, get_args - -import typer - -from huggingface_hub.errors import CLIError, RepositoryNotFoundError, RevisionNotFoundError -from huggingface_hub.hf_api import DatasetSort_T, ExpandDatasetProperty_T - -from ._cli_utils import ( - AuthorOpt, - FilterOpt, - FormatOpt, - LimitOpt, - OutputFormat, - QuietOpt, - RevisionOpt, - SearchOpt, - TokenOpt, - api_object_to_dict, - get_hf_api, - make_expand_properties_parser, - print_list_output, - typer_factory, -) - - -_EXPAND_PROPERTIES = sorted(get_args(ExpandDatasetProperty_T)) -_SORT_OPTIONS = get_args(DatasetSort_T) -DatasetSortEnum = enum.Enum("DatasetSortEnum", {s: s for s in _SORT_OPTIONS}, type=str) # type: ignore[misc] - - -ExpandOpt = Annotated[ - Optional[str], - typer.Option( - help=f"Comma-separated properties to expand. Example: '--expand=downloads,likes,tags'. Valid: {', '.join(_EXPAND_PROPERTIES)}.", - callback=make_expand_properties_parser(_EXPAND_PROPERTIES), - ), -] - - -datasets_cli = typer_factory(help="Interact with datasets on the Hub.") - - -@datasets_cli.command( - "ls", - examples=[ - "hf datasets ls", - "hf datasets ls --sort downloads --limit 10", - 'hf datasets ls --search "code"', - ], -) -def datasets_ls( - search: SearchOpt = None, - author: AuthorOpt = None, - filter: FilterOpt = None, - sort: Annotated[ - Optional[DatasetSortEnum], - typer.Option(help="Sort results."), - ] = None, - limit: LimitOpt = 10, - expand: ExpandOpt = None, - format: FormatOpt = OutputFormat.table, - quiet: QuietOpt = False, - token: TokenOpt = None, -) -> None: - """List datasets on the Hub.""" - api = get_hf_api(token=token) - sort_key = sort.value if sort else None - results = [ - api_object_to_dict(dataset_info) - for dataset_info in api.list_datasets( - filter=filter, author=author, search=search, sort=sort_key, limit=limit, expand=expand - ) - ] - print_list_output(results, format=format, quiet=quiet) - - -@datasets_cli.command( - "info", - examples=[ - "hf datasets info HuggingFaceFW/fineweb", - "hf datasets info my-dataset --expand downloads,likes,tags", - ], -) -def datasets_info( - dataset_id: Annotated[str, typer.Argument(help="The dataset ID (e.g. `username/repo-name`).")], - revision: RevisionOpt = None, - expand: ExpandOpt = None, - token: TokenOpt = None, -) -> None: - """Get info about a dataset on the Hub.""" - api = get_hf_api(token=token) - try: - info = api.dataset_info(repo_id=dataset_id, revision=revision, expand=expand) # type: ignore[arg-type] - except RepositoryNotFoundError as e: - raise CLIError(f"Dataset '{dataset_id}' not found.") from e - except RevisionNotFoundError as e: - raise CLIError(f"Revision '{revision}' not found on '{dataset_id}'.") from e - print(json.dumps(api_object_to_dict(info), indent=2)) diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/download.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/download.py deleted file mode 100644 index 2d89b944d30d2c13e06e9eb4aa6b0d35829a24fd..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/download.py +++ /dev/null @@ -1,197 +0,0 @@ -# coding=utf-8 -# Copyright 202-present, the HuggingFace Inc. team. -# -# 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. -"""Contains command to download files from the Hub with the CLI. - -Usage: - hf download --help - - # Download file - hf download gpt2 config.json - - # Download entire repo - hf download fffiloni/zeroscope --repo-type=space --revision=refs/pr/78 - - # Download repo with filters - hf download gpt2 --include="*.safetensors" - - # Download with token - hf download Wauplin/private-model --token=hf_*** - - # Download quietly (no progress bar, no warnings, only the returned path) - hf download gpt2 config.json --quiet - - # Download to local dir - hf download gpt2 --local-dir=./models/gpt2 -""" - -import warnings -from typing import Annotated, Optional, Union - -import typer - -from huggingface_hub import logging -from huggingface_hub._snapshot_download import snapshot_download -from huggingface_hub.file_download import DryRunFileInfo, hf_hub_download -from huggingface_hub.utils import _format_size, disable_progress_bars, enable_progress_bars, tabulate - -from ._cli_utils import RepoIdArg, RepoTypeOpt, RevisionOpt, TokenOpt - - -DOWNLOAD_EXAMPLES = [ - "hf download meta-llama/Llama-3.2-1B-Instruct", - "hf download meta-llama/Llama-3.2-1B-Instruct config.json tokenizer.json", - 'hf download meta-llama/Llama-3.2-1B-Instruct --include "*.safetensors" --exclude "*.bin"', - "hf download meta-llama/Llama-3.2-1B-Instruct --local-dir ./models/llama", -] - - -logger = logging.get_logger(__name__) - - -def download( - repo_id: RepoIdArg, - filenames: Annotated[ - Optional[list[str]], - typer.Argument( - help="Files to download (e.g. `config.json`, `data/metadata.jsonl`).", - ), - ] = None, - repo_type: RepoTypeOpt = RepoTypeOpt.model, - revision: RevisionOpt = None, - include: Annotated[ - Optional[list[str]], - typer.Option( - help="Glob patterns to include from files to download. eg: *.json", - ), - ] = None, - exclude: Annotated[ - Optional[list[str]], - typer.Option( - help="Glob patterns to exclude from files to download.", - ), - ] = None, - cache_dir: Annotated[ - Optional[str], - typer.Option( - help="Directory where to save files.", - ), - ] = None, - local_dir: Annotated[ - Optional[str], - typer.Option( - help="If set, the downloaded file will be placed under this directory. Check out https://huggingface.co/docs/huggingface_hub/guides/download#download-files-to-a-local-folder for more details.", - ), - ] = None, - force_download: Annotated[ - bool, - typer.Option( - help="If True, the files will be downloaded even if they are already cached.", - ), - ] = False, - dry_run: Annotated[ - bool, - typer.Option( - help="If True, perform a dry run without actually downloading the file.", - ), - ] = False, - token: TokenOpt = None, - quiet: Annotated[ - bool, - typer.Option( - help="If True, progress bars are disabled and only the path to the download files is printed.", - ), - ] = False, - max_workers: Annotated[ - int, - typer.Option( - help="Maximum number of workers to use for downloading files. Default is 8.", - ), - ] = 8, -) -> None: - """Download files from the Hub.""" - - def run_download() -> Union[str, DryRunFileInfo, list[DryRunFileInfo]]: - filenames_list = filenames if filenames is not None else [] - # Warn user if patterns are ignored - if len(filenames_list) > 0: - if include is not None and len(include) > 0: - warnings.warn("Ignoring `--include` since filenames have being explicitly set.") - if exclude is not None and len(exclude) > 0: - warnings.warn("Ignoring `--exclude` since filenames have being explicitly set.") - - # Single file to download: use `hf_hub_download` - if len(filenames_list) == 1: - return hf_hub_download( - repo_id=repo_id, - repo_type=repo_type.value, - revision=revision, - filename=filenames_list[0], - cache_dir=cache_dir, - force_download=force_download, - token=token, - local_dir=local_dir, - library_name="huggingface-cli", - dry_run=dry_run, - ) - - # Otherwise: use `snapshot_download` to ensure all files comes from same revision - if len(filenames_list) == 0: - allow_patterns = include - ignore_patterns = exclude - else: - allow_patterns = filenames_list - ignore_patterns = None - - return snapshot_download( - repo_id=repo_id, - repo_type=repo_type.value, - revision=revision, - allow_patterns=allow_patterns, - ignore_patterns=ignore_patterns, - force_download=force_download, - cache_dir=cache_dir, - token=token, - local_dir=local_dir, - library_name="huggingface-cli", - max_workers=max_workers, - dry_run=dry_run, - ) - - def _print_result(result: Union[str, DryRunFileInfo, list[DryRunFileInfo]]) -> None: - if isinstance(result, str): - print(result) - return - - # Print dry run info - if isinstance(result, DryRunFileInfo): - result = [result] - print( - f"[dry-run] Will download {len([r for r in result if r.will_download])} files (out of {len(result)}) totalling {_format_size(sum(r.file_size for r in result if r.will_download))}." - ) - columns = ["File", "Bytes to download"] - items: list[list[Union[str, int]]] = [] - for info in sorted(result, key=lambda x: x.filename): - items.append([info.filename, _format_size(info.file_size) if info.will_download else "-"]) - print(tabulate(items, headers=columns)) - - if quiet: - disable_progress_bars() - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - _print_result(run_download()) - enable_progress_bars() - else: - _print_result(run_download()) - logging.set_verbosity_warning() diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/hf.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/hf.py deleted file mode 100644 index f044e0a06337adc02c54d52c00fdae3ac211b421..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/hf.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# 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. - -import sys -import traceback - -from huggingface_hub import constants -from huggingface_hub.cli._cli_utils import check_cli_update, typer_factory -from huggingface_hub.cli._errors import format_known_exception -from huggingface_hub.cli.auth import auth_cli -from huggingface_hub.cli.cache import cache_cli -from huggingface_hub.cli.collections import collections_cli -from huggingface_hub.cli.datasets import datasets_cli -from huggingface_hub.cli.download import DOWNLOAD_EXAMPLES, download -from huggingface_hub.cli.inference_endpoints import ie_cli -from huggingface_hub.cli.jobs import jobs_cli -from huggingface_hub.cli.lfs import lfs_enable_largefiles, lfs_multipart_upload -from huggingface_hub.cli.models import models_cli -from huggingface_hub.cli.papers import papers_cli -from huggingface_hub.cli.repo import repo_cli -from huggingface_hub.cli.repo_files import repo_files_cli -from huggingface_hub.cli.skills import skills_cli -from huggingface_hub.cli.spaces import spaces_cli -from huggingface_hub.cli.system import env, version -from huggingface_hub.cli.upload import UPLOAD_EXAMPLES, upload -from huggingface_hub.cli.upload_large_folder import UPLOAD_LARGE_FOLDER_EXAMPLES, upload_large_folder -from huggingface_hub.errors import CLIError -from huggingface_hub.utils import ANSI, logging - - -app = typer_factory(help="Hugging Face Hub CLI") - - -# top level single commands (defined in their respective files) -app.command(examples=DOWNLOAD_EXAMPLES)(download) -app.command(examples=UPLOAD_EXAMPLES)(upload) -app.command(examples=UPLOAD_LARGE_FOLDER_EXAMPLES)(upload_large_folder) - -app.command(topic="help")(env) -app.command(topic="help")(version) - -app.command(hidden=True)(lfs_enable_largefiles) -app.command(hidden=True)(lfs_multipart_upload) - -# command groups -app.add_typer(auth_cli, name="auth") -app.add_typer(cache_cli, name="cache") -app.add_typer(collections_cli, name="collections") -app.add_typer(datasets_cli, name="datasets") -app.add_typer(jobs_cli, name="jobs") -app.add_typer(models_cli, name="models") -app.add_typer(papers_cli, name="papers") -app.add_typer(repo_cli, name="repo") -app.add_typer(repo_files_cli, name="repo-files") -app.add_typer(skills_cli, name="skills") -app.add_typer(spaces_cli, name="spaces") -app.add_typer(ie_cli, name="endpoints") - - -def main(): - if not constants.HF_DEBUG: - logging.set_verbosity_info() - check_cli_update("huggingface_hub") - - try: - app() - except CLIError as e: - print(f"Error: {e}", file=sys.stderr) - if constants.HF_DEBUG: - traceback.print_exc() - else: - print(ANSI.gray("Set HF_DEBUG=1 as environment variable for full traceback.")) - sys.exit(1) - except Exception as e: - message = format_known_exception(e) - if message: - print(f"Error: {message}", file=sys.stderr) - if constants.HF_DEBUG: - traceback.print_exc() - else: - print(ANSI.gray("Set HF_DEBUG=1 as environment variable for full traceback.")) - sys.exit(1) - raise - - -if __name__ == "__main__": - main() diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/inference_endpoints.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/inference_endpoints.py deleted file mode 100644 index 0e4d6ff9141284bc138d353fcc01ab3694f86321..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/inference_endpoints.py +++ /dev/null @@ -1,456 +0,0 @@ -"""CLI commands for Hugging Face Inference Endpoints.""" - -import json -from typing import Annotated, Any, Optional - -import typer - -from huggingface_hub._inference_endpoints import InferenceEndpoint, InferenceEndpointScalingMetric -from huggingface_hub.errors import HfHubHTTPError - -from ._cli_utils import ( - FormatOpt, - OutputFormat, - QuietOpt, - TokenOpt, - get_hf_api, - print_list_output, - typer_factory, -) - - -ie_cli = typer_factory(help="Manage Hugging Face Inference Endpoints.") - -catalog_app = typer_factory(help="Interact with the Inference Endpoints catalog.") - - -NameArg = Annotated[ - str, - typer.Argument(help="Endpoint name."), -] -NameOpt = Annotated[ - Optional[str], - typer.Option(help="Endpoint name."), -] - -NamespaceOpt = Annotated[ - Optional[str], - typer.Option( - help="The namespace associated with the Inference Endpoint. Defaults to the current user's namespace.", - ), -] - - -def _print_endpoint(endpoint: InferenceEndpoint) -> None: - typer.echo(json.dumps(endpoint.raw, indent=2, sort_keys=True)) - - -@ie_cli.command(examples=["hf endpoints ls", "hf endpoints ls --namespace my-org"]) -def ls( - namespace: NamespaceOpt = None, - format: FormatOpt = OutputFormat.table, - quiet: QuietOpt = False, - token: TokenOpt = None, -) -> None: - """Lists all Inference Endpoints for the given namespace.""" - api = get_hf_api(token=token) - try: - endpoints = api.list_inference_endpoints(namespace=namespace, token=token) - except HfHubHTTPError as error: - typer.echo(f"Listing failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - - results = [endpoint.raw for endpoint in endpoints] - - def row_fn(item: dict[str, Any]) -> list[str]: - status = item.get("status", {}) - model = item.get("model", {}) - compute = item.get("compute", {}) - provider = item.get("provider", {}) - return [ - str(item.get("name", "")), - str(model.get("repository", "") if isinstance(model, dict) else ""), - str(status.get("state", "") if isinstance(status, dict) else ""), - str(model.get("task", "") if isinstance(model, dict) else ""), - str(model.get("framework", "") if isinstance(model, dict) else ""), - str(compute.get("instanceType", "") if isinstance(compute, dict) else ""), - str(provider.get("vendor", "") if isinstance(provider, dict) else ""), - str(provider.get("region", "") if isinstance(provider, dict) else ""), - ] - - print_list_output( - items=results, - format=format, - quiet=quiet, - id_key="name", - headers=["NAME", "MODEL", "STATUS", "TASK", "FRAMEWORK", "INSTANCE", "VENDOR", "REGION"], - row_fn=row_fn, - ) - - -@ie_cli.command(name="deploy", examples=["hf endpoints deploy my-endpoint --repo gpt2 --framework pytorch ..."]) -def deploy( - name: NameArg, - repo: Annotated[ - str, - typer.Option( - help="The name of the model repository associated with the Inference Endpoint (e.g. 'openai/gpt-oss-120b').", - ), - ], - framework: Annotated[ - str, - typer.Option( - help="The machine learning framework used for the model (e.g. 'vllm').", - ), - ], - accelerator: Annotated[ - str, - typer.Option( - help="The hardware accelerator to be used for inference (e.g. 'cpu').", - ), - ], - instance_size: Annotated[ - str, - typer.Option( - help="The size or type of the instance to be used for hosting the model (e.g. 'x4').", - ), - ], - instance_type: Annotated[ - str, - typer.Option( - help="The cloud instance type where the Inference Endpoint will be deployed (e.g. 'intel-icl').", - ), - ], - region: Annotated[ - str, - typer.Option( - help="The cloud region in which the Inference Endpoint will be created (e.g. 'us-east-1').", - ), - ], - vendor: Annotated[ - str, - typer.Option( - help="The cloud provider or vendor where the Inference Endpoint will be hosted (e.g. 'aws').", - ), - ], - *, - namespace: NamespaceOpt = None, - task: Annotated[ - Optional[str], - typer.Option( - help="The task on which to deploy the model (e.g. 'text-classification').", - ), - ] = None, - token: TokenOpt = None, - min_replica: Annotated[ - int, - typer.Option( - help="The minimum number of replicas (instances) to keep running for the Inference Endpoint.", - ), - ] = 1, - max_replica: Annotated[ - int, - typer.Option( - help="The maximum number of replicas (instances) to scale to for the Inference Endpoint.", - ), - ] = 1, - scale_to_zero_timeout: Annotated[ - Optional[int], - typer.Option( - help="The duration in minutes before an inactive endpoint is scaled to zero.", - ), - ] = None, - scaling_metric: Annotated[ - Optional[InferenceEndpointScalingMetric], - typer.Option( - help="The metric reference for scaling.", - ), - ] = None, - scaling_threshold: Annotated[ - Optional[float], - typer.Option( - help="The scaling metric threshold used to trigger a scale up. Ignored when scaling metric is not provided.", - ), - ] = None, -) -> None: - """Deploy an Inference Endpoint from a Hub repository.""" - api = get_hf_api(token=token) - endpoint = api.create_inference_endpoint( - name=name, - repository=repo, - framework=framework, - accelerator=accelerator, - instance_size=instance_size, - instance_type=instance_type, - region=region, - vendor=vendor, - namespace=namespace, - task=task, - token=token, - min_replica=min_replica, - max_replica=max_replica, - scaling_metric=scaling_metric, - scaling_threshold=scaling_threshold, - scale_to_zero_timeout=scale_to_zero_timeout, - ) - - _print_endpoint(endpoint) - - -@catalog_app.command(name="deploy", examples=["hf endpoints catalog deploy --repo meta-llama/Llama-3.2-1B-Instruct"]) -def deploy_from_catalog( - repo: Annotated[ - str, - typer.Option( - help="The name of the model repository associated with the Inference Endpoint (e.g. 'openai/gpt-oss-120b').", - ), - ], - name: NameOpt = None, - namespace: NamespaceOpt = None, - token: TokenOpt = None, -) -> None: - """Deploy an Inference Endpoint from the Model Catalog.""" - api = get_hf_api(token=token) - try: - endpoint = api.create_inference_endpoint_from_catalog( - repo_id=repo, - name=name, - namespace=namespace, - token=token, - ) - except HfHubHTTPError as error: - typer.echo(f"Deployment failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - - _print_endpoint(endpoint) - - -def list_catalog( - token: TokenOpt = None, -) -> None: - """List available Catalog models.""" - api = get_hf_api(token=token) - try: - models = api.list_inference_catalog(token=token) - except HfHubHTTPError as error: - typer.echo(f"Catalog fetch failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - - typer.echo(json.dumps({"models": models}, indent=2, sort_keys=True)) - - -catalog_app.command(name="ls", examples=["hf endpoints catalog ls"])(list_catalog) -ie_cli.command(name="list-catalog", hidden=True)(list_catalog) - - -ie_cli.add_typer(catalog_app, name="catalog") - - -@ie_cli.command(examples=["hf endpoints describe my-endpoint"]) -def describe( - name: NameArg, - namespace: NamespaceOpt = None, - token: TokenOpt = None, -) -> None: - """Get information about an existing endpoint.""" - api = get_hf_api(token=token) - try: - endpoint = api.get_inference_endpoint(name=name, namespace=namespace, token=token) - except HfHubHTTPError as error: - typer.echo(f"Fetch failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - - _print_endpoint(endpoint) - - -@ie_cli.command(examples=["hf endpoints update my-endpoint --min-replica 2"]) -def update( - name: NameArg, - namespace: NamespaceOpt = None, - repo: Annotated[ - Optional[str], - typer.Option( - help="The name of the model repository associated with the Inference Endpoint (e.g. 'openai/gpt-oss-120b').", - ), - ] = None, - accelerator: Annotated[ - Optional[str], - typer.Option( - help="The hardware accelerator to be used for inference (e.g. 'cpu').", - ), - ] = None, - instance_size: Annotated[ - Optional[str], - typer.Option( - help="The size or type of the instance to be used for hosting the model (e.g. 'x4').", - ), - ] = None, - instance_type: Annotated[ - Optional[str], - typer.Option( - help="The cloud instance type where the Inference Endpoint will be deployed (e.g. 'intel-icl').", - ), - ] = None, - framework: Annotated[ - Optional[str], - typer.Option( - help="The machine learning framework used for the model (e.g. 'custom').", - ), - ] = None, - revision: Annotated[ - Optional[str], - typer.Option( - help="The specific model revision to deploy on the Inference Endpoint (e.g. '6c0e6080953db56375760c0471a8c5f2929baf11').", - ), - ] = None, - task: Annotated[ - Optional[str], - typer.Option( - help="The task on which to deploy the model (e.g. 'text-classification').", - ), - ] = None, - min_replica: Annotated[ - Optional[int], - typer.Option( - help="The minimum number of replicas (instances) to keep running for the Inference Endpoint.", - ), - ] = None, - max_replica: Annotated[ - Optional[int], - typer.Option( - help="The maximum number of replicas (instances) to scale to for the Inference Endpoint.", - ), - ] = None, - scale_to_zero_timeout: Annotated[ - Optional[int], - typer.Option( - help="The duration in minutes before an inactive endpoint is scaled to zero.", - ), - ] = None, - scaling_metric: Annotated[ - Optional[InferenceEndpointScalingMetric], - typer.Option( - help="The metric reference for scaling.", - ), - ] = None, - scaling_threshold: Annotated[ - Optional[float], - typer.Option( - help="The scaling metric threshold used to trigger a scale up. Ignored when scaling metric is not provided.", - ), - ] = None, - token: TokenOpt = None, -) -> None: - """Update an existing endpoint.""" - api = get_hf_api(token=token) - try: - endpoint = api.update_inference_endpoint( - name=name, - namespace=namespace, - repository=repo, - framework=framework, - revision=revision, - task=task, - accelerator=accelerator, - instance_size=instance_size, - instance_type=instance_type, - min_replica=min_replica, - max_replica=max_replica, - scale_to_zero_timeout=scale_to_zero_timeout, - scaling_metric=scaling_metric, - scaling_threshold=scaling_threshold, - token=token, - ) - except HfHubHTTPError as error: - typer.echo(f"Update failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - _print_endpoint(endpoint) - - -@ie_cli.command(examples=["hf endpoints delete my-endpoint"]) -def delete( - name: NameArg, - namespace: NamespaceOpt = None, - yes: Annotated[ - bool, - typer.Option("--yes", help="Skip confirmation prompts."), - ] = False, - token: TokenOpt = None, -) -> None: - """Delete an Inference Endpoint permanently.""" - if not yes: - confirmation = typer.prompt(f"Delete endpoint '{name}'? Type the name to confirm.") - if confirmation != name: - typer.echo("Aborted.") - raise typer.Exit(code=2) - - api = get_hf_api(token=token) - try: - api.delete_inference_endpoint(name=name, namespace=namespace, token=token) - except HfHubHTTPError as error: - typer.echo(f"Delete failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - - typer.echo(f"Deleted '{name}'.") - - -@ie_cli.command(examples=["hf endpoints pause my-endpoint"]) -def pause( - name: NameArg, - namespace: NamespaceOpt = None, - token: TokenOpt = None, -) -> None: - """Pause an Inference Endpoint.""" - api = get_hf_api(token=token) - try: - endpoint = api.pause_inference_endpoint(name=name, namespace=namespace, token=token) - except HfHubHTTPError as error: - typer.echo(f"Pause failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - - _print_endpoint(endpoint) - - -@ie_cli.command(examples=["hf endpoints resume my-endpoint"]) -def resume( - name: NameArg, - namespace: NamespaceOpt = None, - fail_if_already_running: Annotated[ - bool, - typer.Option( - "--fail-if-already-running", - help="If `True`, the method will raise an error if the Inference Endpoint is already running.", - ), - ] = False, - token: TokenOpt = None, -) -> None: - """Resume an Inference Endpoint.""" - api = get_hf_api(token=token) - try: - endpoint = api.resume_inference_endpoint( - name=name, - namespace=namespace, - token=token, - running_ok=not fail_if_already_running, - ) - except HfHubHTTPError as error: - typer.echo(f"Resume failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - _print_endpoint(endpoint) - - -@ie_cli.command(examples=["hf endpoints scale-to-zero my-endpoint"]) -def scale_to_zero( - name: NameArg, - namespace: NamespaceOpt = None, - token: TokenOpt = None, -) -> None: - """Scale an Inference Endpoint to zero.""" - api = get_hf_api(token=token) - try: - endpoint = api.scale_to_zero_inference_endpoint(name=name, namespace=namespace, token=token) - except HfHubHTTPError as error: - typer.echo(f"Scale To Zero failed: {error}") - raise typer.Exit(code=error.response.status_code) from error - - _print_endpoint(endpoint) diff --git a/venv/lib/python3.10/site-packages/huggingface_hub/cli/jobs.py b/venv/lib/python3.10/site-packages/huggingface_hub/cli/jobs.py deleted file mode 100644 index a36c34c152bdb7720e9f02b47b8d1c8a49bcf817..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/huggingface_hub/cli/jobs.py +++ /dev/null @@ -1,1078 +0,0 @@ -# Copyright 2025 The HuggingFace Team. All rights reserved. -# -# 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. -"""Contains commands to interact with jobs on the Hugging Face Hub. - -Usage: - # run a job - hf jobs run - - # List running or completed jobs - hf jobs ps [-a] [-f key=value] [--format TEMPLATE] - - # Stream logs from a job - hf jobs logs - - # Stream resources usage stats and metrics from a job - hf jobs stats - - # Inspect detailed information about a job - hf jobs inspect - - # Cancel a running job - hf jobs cancel - - # List available hardware options - hf jobs hardware - - # Run a UV script - hf jobs uv run ') - # => <script> do_nasty_stuff() </script> - # sanitize_html('Click here for $100') - # => Click here for $100 - def sanitize_token(self, token): - - # accommodate filters which use token_type differently - token_type = token["type"] - if token_type in ("StartTag", "EndTag", "EmptyTag"): - name = token["name"] - namespace = token["namespace"] - if ((namespace, name) in self.allowed_elements or - (namespace is None and - (namespaces["html"], name) in self.allowed_elements)): - return self.allowed_token(token) - else: - return self.disallowed_token(token) - elif token_type == "Comment": - pass - else: - return token - - def allowed_token(self, token): - if "data" in token: - attrs = token["data"] - attr_names = set(attrs.keys()) - - # Remove forbidden attributes - for to_remove in (attr_names - self.allowed_attributes): - del token["data"][to_remove] - attr_names.remove(to_remove) - - # Remove attributes with disallowed URL values - for attr in (attr_names & self.attr_val_is_uri): - assert attr in attrs - # I don't have a clue where this regexp comes from or why it matches those - # characters, nor why we call unescape. I just know it's always been here. - # Should you be worried by this comment in a sanitizer? Yes. On the other hand, all - # this will do is remove *more* than it otherwise would. - val_unescaped = re.sub("[`\x00-\x20\x7f-\xa0\\s]+", '', - unescape(attrs[attr])).lower() - # remove replacement characters from unescaped characters - val_unescaped = val_unescaped.replace("\ufffd", "") - try: - uri = urlparse.urlparse(val_unescaped) - except ValueError: - uri = None - del attrs[attr] - if uri and uri.scheme: - if uri.scheme not in self.allowed_protocols: - del attrs[attr] - if uri.scheme == 'data': - m = data_content_type.match(uri.path) - if not m: - del attrs[attr] - elif m.group('content_type') not in self.allowed_content_types: - del attrs[attr] - - for attr in self.svg_attr_val_allows_ref: - if attr in attrs: - attrs[attr] = re.sub(r'url\s*\(\s*[^#\s][^)]+?\)', - ' ', - unescape(attrs[attr])) - if (token["name"] in self.svg_allow_local_href and - (namespaces['xlink'], 'href') in attrs and re.search(r'^\s*[^#\s].*', - attrs[(namespaces['xlink'], 'href')])): - del attrs[(namespaces['xlink'], 'href')] - if (None, 'style') in attrs: - attrs[(None, 'style')] = self.sanitize_css(attrs[(None, 'style')]) - token["data"] = attrs - return token - - def disallowed_token(self, token): - token_type = token["type"] - if token_type == "EndTag": - token["data"] = "" % token["name"] - elif token["data"]: - assert token_type in ("StartTag", "EmptyTag") - attrs = [] - for (ns, name), v in token["data"].items(): - attrs.append(' %s="%s"' % (name if ns is None else "%s:%s" % (prefixes[ns], name), escape(v))) - token["data"] = "<%s%s>" % (token["name"], ''.join(attrs)) - else: - token["data"] = "<%s>" % token["name"] - if token.get("selfClosing"): - token["data"] = token["data"][:-1] + "/>" - - token["type"] = "Characters" - - del token["name"] - return token - - def sanitize_css(self, style): - # disallow urls - style = re.compile(r'url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ', style) - - # gauntlet - if not re.match(r"""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): - return '' - if not re.match(r"^\s*([-\w]+\s*:[^:;]*(;\s*|$))*$", style): - return '' - - clean = [] - for prop, value in re.findall(r"([-\w]+)\s*:\s*([^:;]*)", style): - if not value: - continue - if prop.lower() in self.allowed_css_properties: - clean.append(prop + ': ' + value + ';') - elif prop.split('-')[0].lower() in ['background', 'border', 'margin', - 'padding']: - for keyword in value.split(): - if keyword not in self.allowed_css_keywords and \ - not re.match(r"^(#[0-9a-fA-F]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$", keyword): # noqa - break - else: - clean.append(prop + ': ' + value + ';') - elif prop.lower() in self.allowed_svg_properties: - clean.append(prop + ': ' + value + ';') - - return ' '.join(clean) diff --git a/venv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/whitespace.py b/venv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/whitespace.py deleted file mode 100644 index 0d12584b45995d35110f75af00193fdad0fa10f4..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/pip/_vendor/html5lib/filters/whitespace.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -import re - -from . import base -from ..constants import rcdataElements, spaceCharacters -spaceCharacters = "".join(spaceCharacters) - -SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) - - -class Filter(base.Filter): - """Collapses whitespace except in pre, textarea, and script elements""" - spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) - - def __iter__(self): - preserve = 0 - for token in base.Filter.__iter__(self): - type = token["type"] - if type == "StartTag" \ - and (preserve or token["name"] in self.spacePreserveElements): - preserve += 1 - - elif type == "EndTag" and preserve: - preserve -= 1 - - elif not preserve and type == "SpaceCharacters" and token["data"]: - # Test on token["data"] above to not introduce spaces where there were not - token["data"] = " " - - elif not preserve and type == "Characters": - token["data"] = collapse_spaces(token["data"]) - - yield token - - -def collapse_spaces(text): - return SPACES_REGEX.sub(' ', text) diff --git a/venv/lib/python3.10/site-packages/pip/_vendor/html5lib/html5parser.py b/venv/lib/python3.10/site-packages/pip/_vendor/html5lib/html5parser.py deleted file mode 100644 index d06784f3d254176d1bd125cfd4d3af7f13005387..0000000000000000000000000000000000000000 --- a/venv/lib/python3.10/site-packages/pip/_vendor/html5lib/html5parser.py +++ /dev/null @@ -1,2795 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals -from pip._vendor.six import with_metaclass, viewkeys - -import types - -from . import _inputstream -from . import _tokenizer - -from . import treebuilders -from .treebuilders.base import Marker - -from . import _utils -from .constants import ( - spaceCharacters, asciiUpper2Lower, - specialElements, headingElements, cdataElements, rcdataElements, - tokenTypes, tagTokenTypes, - namespaces, - htmlIntegrationPointElements, mathmlTextIntegrationPointElements, - adjustForeignAttributes as adjustForeignAttributesMap, - adjustMathMLAttributes, adjustSVGAttributes, - E, - _ReparseException -) - - -def parse(doc, treebuilder="etree", namespaceHTMLElements=True, **kwargs): - """Parse an HTML document as a string or file-like object into a tree - - :arg doc: the document to parse as a string or file-like object - - :arg treebuilder: the treebuilder to use when parsing - - :arg namespaceHTMLElements: whether or not to namespace HTML elements - - :returns: parsed tree - - Example: - - >>> from html5lib.html5parser import parse - >>> parse('

This is a doc

') - - - """ - tb = treebuilders.getTreeBuilder(treebuilder) - p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) - return p.parse(doc, **kwargs) - - -def parseFragment(doc, container="div", treebuilder="etree", namespaceHTMLElements=True, **kwargs): - """Parse an HTML fragment as a string or file-like object into a tree - - :arg doc: the fragment to parse as a string or file-like object - - :arg container: the container context to parse the fragment in - - :arg treebuilder: the treebuilder to use when parsing - - :arg namespaceHTMLElements: whether or not to namespace HTML elements - - :returns: parsed tree - - Example: - - >>> from html5lib.html5libparser import parseFragment - >>> parseFragment('this is a fragment') - - - """ - tb = treebuilders.getTreeBuilder(treebuilder) - p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) - return p.parseFragment(doc, container=container, **kwargs) - - -def method_decorator_metaclass(function): - class Decorated(type): - def __new__(meta, classname, bases, classDict): - for attributeName, attribute in classDict.items(): - if isinstance(attribute, types.FunctionType): - attribute = function(attribute) - - classDict[attributeName] = attribute - return type.__new__(meta, classname, bases, classDict) - return Decorated - - -class HTMLParser(object): - """HTML parser - - Generates a tree structure from a stream of (possibly malformed) HTML. - - """ - - def __init__(self, tree=None, strict=False, namespaceHTMLElements=True, debug=False): - """ - :arg tree: a treebuilder class controlling the type of tree that will be - returned. Built in treebuilders can be accessed through - html5lib.treebuilders.getTreeBuilder(treeType) - - :arg strict: raise an exception when a parse error is encountered - - :arg namespaceHTMLElements: whether or not to namespace HTML elements - - :arg debug: whether or not to enable debug mode which logs things - - Example: - - >>> from html5lib.html5parser import HTMLParser - >>> parser = HTMLParser() # generates parser with etree builder - >>> parser = HTMLParser('lxml', strict=True) # generates parser with lxml builder which is strict - - """ - - # Raise an exception on the first error encountered - self.strict = strict - - if tree is None: - tree = treebuilders.getTreeBuilder("etree") - self.tree = tree(namespaceHTMLElements) - self.errors = [] - - self.phases = {name: cls(self, self.tree) for name, cls in - getPhases(debug).items()} - - def _parse(self, stream, innerHTML=False, container="div", scripting=False, **kwargs): - - self.innerHTMLMode = innerHTML - self.container = container - self.scripting = scripting - self.tokenizer = _tokenizer.HTMLTokenizer(stream, parser=self, **kwargs) - self.reset() - - try: - self.mainLoop() - except _ReparseException: - self.reset() - self.mainLoop() - - def reset(self): - self.tree.reset() - self.firstStartTag = False - self.errors = [] - self.log = [] # only used with debug mode - # "quirks" / "limited quirks" / "no quirks" - self.compatMode = "no quirks" - - if self.innerHTMLMode: - self.innerHTML = self.container.lower() - - if self.innerHTML in cdataElements: - self.tokenizer.state = self.tokenizer.rcdataState - elif self.innerHTML in rcdataElements: - self.tokenizer.state = self.tokenizer.rawtextState - elif self.innerHTML == 'plaintext': - self.tokenizer.state = self.tokenizer.plaintextState - else: - # state already is data state - # self.tokenizer.state = self.tokenizer.dataState - pass - self.phase = self.phases["beforeHtml"] - self.phase.insertHtmlElement() - self.resetInsertionMode() - else: - self.innerHTML = False # pylint:disable=redefined-variable-type - self.phase = self.phases["initial"] - - self.lastPhase = None - - self.beforeRCDataPhase = None - - self.framesetOK = True - - @property - def documentEncoding(self): - """Name of the character encoding that was used to decode the input stream, or - :obj:`None` if that is not determined yet - - """ - if not hasattr(self, 'tokenizer'): - return None - return self.tokenizer.stream.charEncoding[0].name - - def isHTMLIntegrationPoint(self, element): - if (element.name == "annotation-xml" and - element.namespace == namespaces["mathml"]): - return ("encoding" in element.attributes and - element.attributes["encoding"].translate( - asciiUpper2Lower) in - ("text/html", "application/xhtml+xml")) - else: - return (element.namespace, element.name) in htmlIntegrationPointElements - - def isMathMLTextIntegrationPoint(self, element): - return (element.namespace, element.name) in mathmlTextIntegrationPointElements - - def mainLoop(self): - CharactersToken = tokenTypes["Characters"] - SpaceCharactersToken = tokenTypes["SpaceCharacters"] - StartTagToken = tokenTypes["StartTag"] - EndTagToken = tokenTypes["EndTag"] - CommentToken = tokenTypes["Comment"] - DoctypeToken = tokenTypes["Doctype"] - ParseErrorToken = tokenTypes["ParseError"] - - for token in self.tokenizer: - prev_token = None - new_token = token - while new_token is not None: - prev_token = new_token - currentNode = self.tree.openElements[-1] if self.tree.openElements else None - currentNodeNamespace = currentNode.namespace if currentNode else None - currentNodeName = currentNode.name if currentNode else None - - type = new_token["type"] - - if type == ParseErrorToken: - self.parseError(new_token["data"], new_token.get("datavars", {})) - new_token = None - else: - if (len(self.tree.openElements) == 0 or - currentNodeNamespace == self.tree.defaultNamespace or - (self.isMathMLTextIntegrationPoint(currentNode) and - ((type == StartTagToken and - token["name"] not in frozenset(["mglyph", "malignmark"])) or - type in (CharactersToken, SpaceCharactersToken))) or - (currentNodeNamespace == namespaces["mathml"] and - currentNodeName == "annotation-xml" and - type == StartTagToken and - token["name"] == "svg") or - (self.isHTMLIntegrationPoint(currentNode) and - type in (StartTagToken, CharactersToken, SpaceCharactersToken))): - phase = self.phase - else: - phase = self.phases["inForeignContent"] - - if type == CharactersToken: - new_token = phase.processCharacters(new_token) - elif type == SpaceCharactersToken: - new_token = phase.processSpaceCharacters(new_token) - elif type == StartTagToken: - new_token = phase.processStartTag(new_token) - elif type == EndTagToken: - new_token = phase.processEndTag(new_token) - elif type == CommentToken: - new_token = phase.processComment(new_token) - elif type == DoctypeToken: - new_token = phase.processDoctype(new_token) - - if (type == StartTagToken and prev_token["selfClosing"] and - not prev_token["selfClosingAcknowledged"]): - self.parseError("non-void-element-with-trailing-solidus", - {"name": prev_token["name"]}) - - # When the loop finishes it's EOF - reprocess = True - phases = [] - while reprocess: - phases.append(self.phase) - reprocess = self.phase.processEOF() - if reprocess: - assert self.phase not in phases - - def parse(self, stream, *args, **kwargs): - """Parse a HTML document into a well-formed tree - - :arg stream: a file-like object or string containing the HTML to be parsed - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element). - - :arg scripting: treat noscript elements as if JavaScript was turned on - - :returns: parsed tree - - Example: - - >>> from html5lib.html5parser import HTMLParser - >>> parser = HTMLParser() - >>> parser.parse('

This is a doc

') - - - """ - self._parse(stream, False, None, *args, **kwargs) - return self.tree.getDocument() - - def parseFragment(self, stream, *args, **kwargs): - """Parse a HTML fragment into a well-formed tree fragment - - :arg container: name of the element we're setting the innerHTML - property if set to None, default to 'div' - - :arg stream: a file-like object or string containing the HTML to be parsed - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element) - - :arg scripting: treat noscript elements as if JavaScript was turned on - - :returns: parsed tree - - Example: - - >>> from html5lib.html5libparser import HTMLParser - >>> parser = HTMLParser() - >>> parser.parseFragment('this is a fragment') - - - """ - self._parse(stream, True, *args, **kwargs) - return self.tree.getFragment() - - def parseError(self, errorcode="XXX-undefined-error", datavars=None): - # XXX The idea is to make errorcode mandatory. - if datavars is None: - datavars = {} - self.errors.append((self.tokenizer.stream.position(), errorcode, datavars)) - if self.strict: - raise ParseError(E[errorcode] % datavars) - - def adjustMathMLAttributes(self, token): - adjust_attributes(token, adjustMathMLAttributes) - - def adjustSVGAttributes(self, token): - adjust_attributes(token, adjustSVGAttributes) - - def adjustForeignAttributes(self, token): - adjust_attributes(token, adjustForeignAttributesMap) - - def reparseTokenNormal(self, token): - # pylint:disable=unused-argument - self.parser.phase() - - def resetInsertionMode(self): - # The name of this method is mostly historical. (It's also used in the - # specification.) - last = False - newModes = { - "select": "inSelect", - "td": "inCell", - "th": "inCell", - "tr": "inRow", - "tbody": "inTableBody", - "thead": "inTableBody", - "tfoot": "inTableBody", - "caption": "inCaption", - "colgroup": "inColumnGroup", - "table": "inTable", - "head": "inBody", - "body": "inBody", - "frameset": "inFrameset", - "html": "beforeHead" - } - for node in self.tree.openElements[::-1]: - nodeName = node.name - new_phase = None - if node == self.tree.openElements[0]: - assert self.innerHTML - last = True - nodeName = self.innerHTML - # Check for conditions that should only happen in the innerHTML - # case - if nodeName in ("select", "colgroup", "head", "html"): - assert self.innerHTML - - if not last and node.namespace != self.tree.defaultNamespace: - continue - - if nodeName in newModes: - new_phase = self.phases[newModes[nodeName]] - break - elif last: - new_phase = self.phases["inBody"] - break - - self.phase = new_phase - - def parseRCDataRawtext(self, token, contentType): - # Generic RCDATA/RAWTEXT Parsing algorithm - assert contentType in ("RAWTEXT", "RCDATA") - - self.tree.insertElement(token) - - if contentType == "RAWTEXT": - self.tokenizer.state = self.tokenizer.rawtextState - else: - self.tokenizer.state = self.tokenizer.rcdataState - - self.originalPhase = self.phase - - self.phase = self.phases["text"] - - -@_utils.memoize -def getPhases(debug): - def log(function): - """Logger that records which phase processes each token""" - type_names = {value: key for key, value in tokenTypes.items()} - - def wrapped(self, *args, **kwargs): - if function.__name__.startswith("process") and len(args) > 0: - token = args[0] - info = {"type": type_names[token['type']]} - if token['type'] in tagTokenTypes: - info["name"] = token['name'] - - self.parser.log.append((self.parser.tokenizer.state.__name__, - self.parser.phase.__class__.__name__, - self.__class__.__name__, - function.__name__, - info)) - return function(self, *args, **kwargs) - else: - return function(self, *args, **kwargs) - return wrapped - - def getMetaclass(use_metaclass, metaclass_func): - if use_metaclass: - return method_decorator_metaclass(metaclass_func) - else: - return type - - # pylint:disable=unused-argument - class Phase(with_metaclass(getMetaclass(debug, log))): - """Base class for helper object that implements each phase of processing - """ - __slots__ = ("parser", "tree", "__startTagCache", "__endTagCache") - - def __init__(self, parser, tree): - self.parser = parser - self.tree = tree - self.__startTagCache = {} - self.__endTagCache = {} - - def processEOF(self): - raise NotImplementedError - - def processComment(self, token): - # For most phases the following is correct. Where it's not it will be - # overridden. - self.tree.insertComment(token, self.tree.openElements[-1]) - - def processDoctype(self, token): - self.parser.parseError("unexpected-doctype") - - def processCharacters(self, token): - self.tree.insertText(token["data"]) - - def processSpaceCharacters(self, token): - self.tree.insertText(token["data"]) - - def processStartTag(self, token): - # Note the caching is done here rather than BoundMethodDispatcher as doing it there - # requires a circular reference to the Phase, and this ends up with a significant - # (CPython 2.7, 3.8) GC cost when parsing many short inputs - name = token["name"] - # In Py2, using `in` is quicker in general than try/except KeyError - # In Py3, `in` is quicker when there are few cache hits (typically short inputs) - if name in self.__startTagCache: - func = self.__startTagCache[name] - else: - func = self.__startTagCache[name] = self.startTagHandler[name] - # bound the cache size in case we get loads of unknown tags - while len(self.__startTagCache) > len(self.startTagHandler) * 1.1: - # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7 - self.__startTagCache.pop(next(iter(self.__startTagCache))) - return func(token) - - def startTagHtml(self, token): - if not self.parser.firstStartTag and token["name"] == "html": - self.parser.parseError("non-html-root") - # XXX Need a check here to see if the first start tag token emitted is - # this token... If it's not, invoke self.parser.parseError(). - for attr, value in token["data"].items(): - if attr not in self.tree.openElements[0].attributes: - self.tree.openElements[0].attributes[attr] = value - self.parser.firstStartTag = False - - def processEndTag(self, token): - # Note the caching is done here rather than BoundMethodDispatcher as doing it there - # requires a circular reference to the Phase, and this ends up with a significant - # (CPython 2.7, 3.8) GC cost when parsing many short inputs - name = token["name"] - # In Py2, using `in` is quicker in general than try/except KeyError - # In Py3, `in` is quicker when there are few cache hits (typically short inputs) - if name in self.__endTagCache: - func = self.__endTagCache[name] - else: - func = self.__endTagCache[name] = self.endTagHandler[name] - # bound the cache size in case we get loads of unknown tags - while len(self.__endTagCache) > len(self.endTagHandler) * 1.1: - # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7 - self.__endTagCache.pop(next(iter(self.__endTagCache))) - return func(token) - - class InitialPhase(Phase): - __slots__ = tuple() - - def processSpaceCharacters(self, token): - pass - - def processComment(self, token): - self.tree.insertComment(token, self.tree.document) - - def processDoctype(self, token): - name = token["name"] - publicId = token["publicId"] - systemId = token["systemId"] - correct = token["correct"] - - if (name != "html" or publicId is not None or - systemId is not None and systemId != "about:legacy-compat"): - self.parser.parseError("unknown-doctype") - - if publicId is None: - publicId = "" - - self.tree.insertDoctype(token) - - if publicId != "": - publicId = publicId.translate(asciiUpper2Lower) - - if (not correct or token["name"] != "html" or - publicId.startswith( - ("+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", - "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", - "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", - "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", - "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", - "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", - "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//")) or - publicId in ("-//w3o//dtd w3 html strict 3.0//en//", - "-/w3c/dtd html 4.0 transitional/en", - "html") or - publicId.startswith( - ("-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//")) and - systemId is None or - systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"): - self.parser.compatMode = "quirks" - elif (publicId.startswith( - ("-//w3c//dtd xhtml 1.0 frameset//", - "-//w3c//dtd xhtml 1.0 transitional//")) or - publicId.startswith( - ("-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//")) and - systemId is not None): - self.parser.compatMode = "limited quirks" - - self.parser.phase = self.parser.phases["beforeHtml"] - - def anythingElse(self): - self.parser.compatMode = "quirks" - self.parser.phase = self.parser.phases["beforeHtml"] - - def processCharacters(self, token): - self.parser.parseError("expected-doctype-but-got-chars") - self.anythingElse() - return token - - def processStartTag(self, token): - self.parser.parseError("expected-doctype-but-got-start-tag", - {"name": token["name"]}) - self.anythingElse() - return token - - def processEndTag(self, token): - self.parser.parseError("expected-doctype-but-got-end-tag", - {"name": token["name"]}) - self.anythingElse() - return token - - def processEOF(self): - self.parser.parseError("expected-doctype-but-got-eof") - self.anythingElse() - return True - - class BeforeHtmlPhase(Phase): - __slots__ = tuple() - - # helper methods - def insertHtmlElement(self): - self.tree.insertRoot(impliedTagToken("html", "StartTag")) - self.parser.phase = self.parser.phases["beforeHead"] - - # other - def processEOF(self): - self.insertHtmlElement() - return True - - def processComment(self, token): - self.tree.insertComment(token, self.tree.document) - - def processSpaceCharacters(self, token): - pass - - def processCharacters(self, token): - self.insertHtmlElement() - return token - - def processStartTag(self, token): - if token["name"] == "html": - self.parser.firstStartTag = True - self.insertHtmlElement() - return token - - def processEndTag(self, token): - if token["name"] not in ("head", "body", "html", "br"): - self.parser.parseError("unexpected-end-tag-before-html", - {"name": token["name"]}) - else: - self.insertHtmlElement() - return token - - class BeforeHeadPhase(Phase): - __slots__ = tuple() - - def processEOF(self): - self.startTagHead(impliedTagToken("head", "StartTag")) - return True - - def processSpaceCharacters(self, token): - pass - - def processCharacters(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagHead(self, token): - self.tree.insertElement(token) - self.tree.headPointer = self.tree.openElements[-1] - self.parser.phase = self.parser.phases["inHead"] - - def startTagOther(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def endTagImplyHead(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def endTagOther(self, token): - self.parser.parseError("end-tag-after-implied-root", - {"name": token["name"]}) - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - ("head", startTagHead) - ]) - startTagHandler.default = startTagOther - - endTagHandler = _utils.MethodDispatcher([ - (("head", "body", "html", "br"), endTagImplyHead) - ]) - endTagHandler.default = endTagOther - - class InHeadPhase(Phase): - __slots__ = tuple() - - # the real thing - def processEOF(self): - self.anythingElse() - return True - - def processCharacters(self, token): - self.anythingElse() - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagHead(self, token): - self.parser.parseError("two-heads-are-not-better-than-one") - - def startTagBaseLinkCommand(self, token): - self.tree.insertElement(token) - self.tree.openElements.pop() - token["selfClosingAcknowledged"] = True - - def startTagMeta(self, token): - self.tree.insertElement(token) - self.tree.openElements.pop() - token["selfClosingAcknowledged"] = True - - attributes = token["data"] - if self.parser.tokenizer.stream.charEncoding[1] == "tentative": - if "charset" in attributes: - self.parser.tokenizer.stream.changeEncoding(attributes["charset"]) - elif ("content" in attributes and - "http-equiv" in attributes and - attributes["http-equiv"].lower() == "content-type"): - # Encoding it as UTF-8 here is a hack, as really we should pass - # the abstract Unicode string, and just use the - # ContentAttrParser on that, but using UTF-8 allows all chars - # to be encoded and as a ASCII-superset works. - data = _inputstream.EncodingBytes(attributes["content"].encode("utf-8")) - parser = _inputstream.ContentAttrParser(data) - codec = parser.parse() - self.parser.tokenizer.stream.changeEncoding(codec) - - def startTagTitle(self, token): - self.parser.parseRCDataRawtext(token, "RCDATA") - - def startTagNoFramesStyle(self, token): - # Need to decide whether to implement the scripting-disabled case - self.parser.parseRCDataRawtext(token, "RAWTEXT") - - def startTagNoscript(self, token): - if self.parser.scripting: - self.parser.parseRCDataRawtext(token, "RAWTEXT") - else: - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inHeadNoscript"] - - def startTagScript(self, token): - self.tree.insertElement(token) - self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState - self.parser.originalPhase = self.parser.phase - self.parser.phase = self.parser.phases["text"] - - def startTagOther(self, token): - self.anythingElse() - return token - - def endTagHead(self, token): - node = self.parser.tree.openElements.pop() - assert node.name == "head", "Expected head got %s" % node.name - self.parser.phase = self.parser.phases["afterHead"] - - def endTagHtmlBodyBr(self, token): - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - self.endTagHead(impliedTagToken("head")) - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - ("title", startTagTitle), - (("noframes", "style"), startTagNoFramesStyle), - ("noscript", startTagNoscript), - ("script", startTagScript), - (("base", "basefont", "bgsound", "command", "link"), - startTagBaseLinkCommand), - ("meta", startTagMeta), - ("head", startTagHead) - ]) - startTagHandler.default = startTagOther - - endTagHandler = _utils.MethodDispatcher([ - ("head", endTagHead), - (("br", "html", "body"), endTagHtmlBodyBr) - ]) - endTagHandler.default = endTagOther - - class InHeadNoscriptPhase(Phase): - __slots__ = tuple() - - def processEOF(self): - self.parser.parseError("eof-in-head-noscript") - self.anythingElse() - return True - - def processComment(self, token): - return self.parser.phases["inHead"].processComment(token) - - def processCharacters(self, token): - self.parser.parseError("char-in-head-noscript") - self.anythingElse() - return token - - def processSpaceCharacters(self, token): - return self.parser.phases["inHead"].processSpaceCharacters(token) - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagBaseLinkCommand(self, token): - return self.parser.phases["inHead"].processStartTag(token) - - def startTagHeadNoscript(self, token): - self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) - - def startTagOther(self, token): - self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) - self.anythingElse() - return token - - def endTagNoscript(self, token): - node = self.parser.tree.openElements.pop() - assert node.name == "noscript", "Expected noscript got %s" % node.name - self.parser.phase = self.parser.phases["inHead"] - - def endTagBr(self, token): - self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - # Caller must raise parse error first! - self.endTagNoscript(impliedTagToken("noscript")) - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - (("basefont", "bgsound", "link", "meta", "noframes", "style"), startTagBaseLinkCommand), - (("head", "noscript"), startTagHeadNoscript), - ]) - startTagHandler.default = startTagOther - - endTagHandler = _utils.MethodDispatcher([ - ("noscript", endTagNoscript), - ("br", endTagBr), - ]) - endTagHandler.default = endTagOther - - class AfterHeadPhase(Phase): - __slots__ = tuple() - - def processEOF(self): - self.anythingElse() - return True - - def processCharacters(self, token): - self.anythingElse() - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagBody(self, token): - self.parser.framesetOK = False - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inBody"] - - def startTagFrameset(self, token): - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inFrameset"] - - def startTagFromHead(self, token): - self.parser.parseError("unexpected-start-tag-out-of-my-head", - {"name": token["name"]}) - self.tree.openElements.append(self.tree.headPointer) - self.parser.phases["inHead"].processStartTag(token) - for node in self.tree.openElements[::-1]: - if node.name == "head": - self.tree.openElements.remove(node) - break - - def startTagHead(self, token): - self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) - - def startTagOther(self, token): - self.anythingElse() - return token - - def endTagHtmlBodyBr(self, token): - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - self.tree.insertElement(impliedTagToken("body", "StartTag")) - self.parser.phase = self.parser.phases["inBody"] - self.parser.framesetOK = True - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - ("body", startTagBody), - ("frameset", startTagFrameset), - (("base", "basefont", "bgsound", "link", "meta", "noframes", "script", - "style", "title"), - startTagFromHead), - ("head", startTagHead) - ]) - startTagHandler.default = startTagOther - endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"), - endTagHtmlBodyBr)]) - endTagHandler.default = endTagOther - - class InBodyPhase(Phase): - # http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody - # the really-really-really-very crazy mode - __slots__ = ("processSpaceCharacters",) - - def __init__(self, *args, **kwargs): - super(InBodyPhase, self).__init__(*args, **kwargs) - # Set this to the default handler - self.processSpaceCharacters = self.processSpaceCharactersNonPre - - def isMatchingFormattingElement(self, node1, node2): - return (node1.name == node2.name and - node1.namespace == node2.namespace and - node1.attributes == node2.attributes) - - # helper - def addFormattingElement(self, token): - self.tree.insertElement(token) - element = self.tree.openElements[-1] - - matchingElements = [] - for node in self.tree.activeFormattingElements[::-1]: - if node is Marker: - break - elif self.isMatchingFormattingElement(node, element): - matchingElements.append(node) - - assert len(matchingElements) <= 3 - if len(matchingElements) == 3: - self.tree.activeFormattingElements.remove(matchingElements[-1]) - self.tree.activeFormattingElements.append(element) - - # the real deal - def processEOF(self): - allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td", - "tfoot", "th", "thead", "tr", "body", - "html")) - for node in self.tree.openElements[::-1]: - if node.name not in allowed_elements: - self.parser.parseError("expected-closing-tag-but-got-eof") - break - # Stop parsing - - def processSpaceCharactersDropNewline(self, token): - # Sometimes (start of
, , and